Re: [Lit.] Buffer overruns

From: infobahn (infobahn_at_btinternet.com)
Date: 01/18/05


Date: Tue, 18 Jan 2005 08:47:58 +0000 (UTC)

David Wagner wrote:
>
> P.S. C doesn't have type-safe opaque types. You can build types and
> hope that no one else will violate the abstraction ('pretty please, don't
> look inside'), but C doesn't provide any way to enforce this.

Maybe I have misunderstood you, but it's certainly possible to
build and implement C types that your user cannot access using
legal C code. Consider the following code, which comprises foo.h,
foo.c, and main.c.

Here's foo.h:

#ifndef FOO_H_
#define FOO_H_ 1

#include <stdio.h>

typedef struct FOO_ FOO;

FOO *CreateFoo(const char *s);
int PrintFoo(FILE *fp, const FOO *f);
void DestroyFoo(FOO **f);

#endif

Here is foo.c:

#include "foo.h"

#include <stdlib.h>
#include <stdio.h>

struct FOO_
{
  int this;
  long that;
  double theother;
};

FOO *CreateFoo(const char *s)
{
  FOO *new = NULL;

  if(s != NULL)
  {
    new = malloc(sizeof *new);
    if(new != NULL)
    {
      char *endptr;
      /* just a demo, not intended to be rock-solid,
       * but here is the right place to *make* the
       * code rock-solid.
       */
      new->this = strtol(s, &endptr, 10);
      s = endptr;
      new->that = strtol(s, &endptr, 10);
      s = endptr;
      new->theother = strtod(s, &endptr);
    }
  }
  return new;
}

int PrintFoo(FILE *fp, const FOO *f)
{
  int rc = -1;
  if(f != NULL && fp != NULL)
  {
    rc = fprintf(fp, "%f %ld %d\n", f->theother, f->that, f->this);
  }
  return rc;
}

void DestroyFoo(FOO **f)
{
    if(f != NULL)
    {
        free(*f);
        *f = NULL;
    }
}

Here is main.c:

#include "foo.h"

int main(void)
{
    FOO *f = CreateFoo("42 12345678 3.14");
    if(f != NULL)
    {
        PrintFoo(stdout, f);
    }
    DestroyFoo(&f);
    return 0;
}

Now here's what you do. You compile foo.c into an object file.
You ship foo.o (or foo.obj, or whatever), together with foo.h.
You also document the interface.

Note that CreateFoo(), which has been implemented in a hurry so
please don't attack it too heavily for being a complete pile of
nonsense, has been carefully *designed* not to give away anything
about the underlying implementation. I could change that easily,
as long as I don't change the interface definition or the
semantics of the input parameter, without affecting the
user-programmer's code. All he will have to do to get the
new behaviour is to re-link against the new object file.

The important point here is that you DO NOT SHIP foo.c to the
user-programmer.

The user-programmer writes main.c for himself or herself or, quite
possibly, themselves. :-)

Note that foo.h doesn't contain any size or member name information
about the FOO type. So the user-programmer cannot instantiate FOO
at all, but he (or she or they) CAN instantiate a pointer to a FOO.

Furthermore, provided the above process has been followed, note that:

  FOO *f;
  f->this = 42;

is not only impossible (because the C programmer doesn't know
what's in FOO) but also illegal (because the compiler doesn't
know what's in FOO either).

So: /either/ C can indeed do "type-safe opaque types" /or/ you
mean something different from me when you say "type-safe opaque
types".



Relevant Pages

  • Re: [C] strcat() question (ongoing)
    ... > At the machine level, yes, basically (depending on your definition ... We can only "PUT" data in / or assign data to variables such as an int or ... foo is an object? ... > house and look on the microwave. ...
    (alt.comp.lang.learn.c-cpp)
  • Re: call of variadic function
    ... arguments that should be passed to this function are of type int. ... You call foo with more arguments than are ... which is the standard way to access arguments of a variadic function ... Here the else clause of my sentence specifies one of the numerous non- ...
    (comp.lang.c)
  • Re: RISC OS modules with stock gcc?
    ... int bar; ... DCD &ff000004 ... IMPORT bar ... EXPORT foo ...
    (comp.sys.acorn.programmer)
  • Re: call of variadic function
    ... arguments that should be passed to this function are of type int. ... call and the definition of function foo itself does NOT produce any ... which is the standard way to access arguments of a variadic function ... Here the else clause of my sentence specifies one of the numerous non- ...
    (comp.lang.c)
  • Re: Dive Into Java?
    ... So it acts as a casting operator. ... class Foo { ... int _arg; ... Foo(int arg) { ...
    (comp.lang.python)

Loading