Skip to content

AlxHnr/CRegion

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

travis codecov license

A free, public-domain region implementation without any dependencies. It conforms strictly to C99 and is valgrind-clean. Allocation failures and arithmetic overflows are handled by calling exit().

Copy the files from src/ into your project and add them to your build script.

Examples

#include "region.h"

CR_Region *r = CR_RegionNew();

char *data = CR_RegionAlloc(r, 1024);

CR_RegionRelease(r); /* If omitted, it will be released trough atexit() */

Callbacks can be attached to regions and will be called when the region gets released:

void cleanup(void *data) { /* ... */ }

Foo *foo = createFoo();

CR_RegionAttach(r, cleanup, foo);

Memory allocated via CR_RegionAlloc() has a fixed size and can not be reallocated. Use CR_RegionAllocGrowable() to get growable memory:

#include "alloc-growable.h"

char *buffer = CR_RegionAllocGrowable(r, 24);

/* Grow the buffer if needed. */
buffer = CR_EnsureCapacity(buffer, 128);

In the example above the lifetime of buffer will be bound to the region r. If r gets released, buffer will also be released. To bind a buffer to the lifetime of the entire program, initialize it to NULL:

static char *buffer = NULL;

buffer = CR_EnsureCapacity(buffer, 128);

Objects with a very short lifetime can be allocated using a memory pool, which allows reusing memory in a region:

#include "mempool.h"

CR_Mempool *int_pool = CR_MempoolNew(r, sizeof(int), NULL, NULL);

int *value = CR_MempoolAlloc(int_pool);
*value = -12;

The lifetime of memory returned from the pool is bound to pool itself, which in turn is bound to the region. Objects can be released manually:

CR_DestroyObject(value);

Objects allocated by the pool can have destructors. To do so, two callbacks can to be provided to the mempool.

The first one will be called when destroying objects explicitly by using CR_DestroyObject(). This callback is allowed to handle errors by calling exit().

The second callback will be called for objects that have not been destroyed explicitly. It will be invoked when the mempool gets released together with its associated region. This callback is not allowed to call exit(), because it may be called while the program is terminating.

The mempool guarantees that only one of these callbacks will be called for the same object.

/* This destructor will be called when an object is passed to
  CR_DestroyObject(). */
int closeFile(void *data)
{
  FileHandle *file = data;
  if(syncToDiskAndClose(file) == ERROR)
  {
    CR_ExitFailure("failed to write important file");
  }

  /* This function returns an int, to have a signature different from the
     other destructor. The returned value will be ignored. */
  return 0;
}

/* This will be called for objects which couldn't be destroyed explicitly
  (e.g. the program called exit() prematurely). It is not allowed to call
  exit() and will be invoked when the mempool (and its owning region) get
  released. */
void freeFile(void *data)
{
  FileHandle *file = data;
  (void)syncToDiskAndClose(file);
}

CR_Mempool *file_pool = CR_MempoolNew(r, sizeof(FileHandle), closeFile, freeFile);

FileHandle *file = CR_MempoolAlloc(file_pool);
file->stream = openStream("/dev/null");

CR_EnableObjectDestructor(file); /* Must be done explicitly after the
                                    object is fully constructed */

Debugging and sanitizing

This library allocates mostly from continuous memory, which makes it impossible for debugging tools to detect overflows. In order to use such tools, continuous memory has to be disabled. This can be achieved by defining CREGION_ALWAYS_FRESH_MALLOC during compilation. Doing so causes CRegion to return new, fresh memory from raw malloc on every single allocation.

Caveats

Runtime leak-detectors are not useful because CRegion will clean up everything when the program terminates. Changing this behaviour would require invasive modifications to the library and to code using this library. This would break the way CRegion is intended to be used. CRegion is not thread-safe.