Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verifying that memory has been initialized in C

I've written an API that requires a context to be initialized and thereafter passed into every API call. The caller allocates the memory for the context, and then passes it to the init function with other parameters that describe how they want later API calls to behave. The context is opaque, so the client can't really muck around in there; it's only intended for the internal use of the API functions.

The problem I'm running into is that callers are allocating the context, but not initializing it. As a result, subsequent API functions are referring to meaningless garbage as if it was a real context.

I'm looking for a way to verify that the context passed into an API function has actually been initialized. I'm not sure if this is possible. Two ideas I've thought of are:

  1. Use a pre-defined constant and store it in a "magic" field of the context to be verified at API invocation time.
  2. Use a checksum of the contents of the context, storing this in the "magic" field and verifying it at invocation time.

Unfortunately I know that either one of these options could result in a false positive verification, either because random crap in memory matches the "magic" number, or because the context happens to occupy the same space as a previously initialized context. I think the latter scenario is more likely.

Does this simply boil down to a question of probability? That I can avoid false positives in most cases, but not all? Is it worth using a system that merely gives me a reasonable probability of accuracy, or would this just make debugging other problems more difficult?

like image 503
Paul Holden Avatar asked Jan 24 '09 07:01

Paul Holden


2 Answers

Best solution, I think, is add create()/delete() functions to your API and use create to allocate and initialize the structure. You can put a signature at the start of the structure to verify that the pointer you are passed points to memory allocated with create() and use delete() to overwrite the signature (or entire buffer) before freeing the memory.

You can't actually avoid false positives in C because the caller malloc'd memory that "happened" to start with your signature; but make you signature reasonably long (say 8 bytes) and the odds are low. Taking allocation out of the hands of the caller by providing a create() function will go a long way, though.

And, yeah, your biggest risk is that an initialized buffer is free'd without using delete(), and a subsequent malloc happens to reuse that memory block.

like image 127
Lawrence Dol Avatar answered Sep 22 '22 01:09

Lawrence Dol


Your context variable is probably at the moment some kind of pointer to allocated memory. Instead of this, make it a token or handle that can be explicitly verified. Every time a context is initialised, you return a new token (not the actual context object) and store that token in an internal list. Then, when a client gives you a context later on, you check it is valid by looking in the list. If it is, the token can then be converted to the actual context and used, otherwise an error is returned.

typedef Context long;

typedef std::map<Context, InternalContext> Contexts;
Contexts _contexts;

Context nextContext()
{
  static Context next=0;
  return next++;
}

Context initialise()
{
  Context c=nextContext();
  _contexts.insert(make_pair(c, new InternalContext));
  return c;
}

void doSomethingWithContext(Context c)
{
  Contexts::iterator it=_ _contexts.find(c);
  if (it==_contexts.end())
    throw "invalid context";
  // otherwise do stuff with the valid context variable
  InternalContext *internalContext=*it.second;
}

With this method, there is no risk of an invalid memory access as you will only correctly use valid context references.

like image 27
1800 INFORMATION Avatar answered Sep 19 '22 01:09

1800 INFORMATION