LoginRegister
About Services Software Resources Jobs Contact
libstent - Eliminate Memory Errors in C

Latest commit: 78577ea by Karsten Pedersen on 2023-02-07

Message: Added 'using'. Similar to std::shared_ptr aliasing constructor.

$ git clone https://www.thamessoftware.co.uk/git/stent.git

Repository listing: stent
doc
include
src
CMakeLists.txt 1.02 KB
LICENSE 1.27 KB
README.md 3.19 KB

Introduction

By borrowing concepts from std::weak_ptr in C++ (or more closely wxWeakRef from wxWidgets), Memory errors in C can appear in a more deterministic manner without severely impacting the design of program code.

Rather than using a raw pointer, the developer uses a pointer wrapper which is guaranteed to return NULL as soon as the original data being pointed to is freed. Rather than return NULL, Stent instead displays a useful debug error and aborts the program, letting the developer know that there is an issue with the code.

Note: Stent is intended to be enabled only during debugging. For release builds, it can be disabled and the program will incur no additional costs to the performance at runtime.

Using Stent

There are a few considerations that a developer needs to make before using Stent. The following instructions should provide a brief overview of the steps required. However, a quick look through the src/tests/ref.c program should also explain these concepts.

Include the "stent.h" header file.

#define STENT_IMPLEMENTATION
#include <stent.h>

Note: Exactly one compilation unit must define STENT_IMPLEMENTATION before including the header in order for the implementation of Stent to be compiled correctly as a header-only library.

Declare a variable to store the pointer:

struct SomeStruct *someStruct = NULL;  // Standard C
ref(SomeStruct) someStruct = NULL;     // Using Stent

To dereference a pointer:

someStruct->someData = 6;    // Standard C
_(someStruct).someData = 6;  // Using Stent

To allocate dynamic memory:

someStruct = calloc(1, sizeof(*someStruct));  // Standard C
someStruct = allocate(SomeStruct);            // Using Stent

To free dynamic memory:

free(someStruct);     // Standard C
release(someStruct);  // Using Stent

Note: When using Stent, any time you subsequently dereference the pointer using _(ptr), it will abort since the memory pointed to is no longer valid. This means that without checking, the program will reliably crash in the debug build.

Forward declaring a structure:

struct SomeStruct;  // Same for both Standard C and Stent

Defining a structure containing a pointer:

struct Test
{
  struct SomeStruct *someStruct;  // Standard C
  ref(SomeStruct) someStruct;     // Using Stent
};

Pass pointer into function (Function prototypes):

void SomeStructProc(struct SomeStruct *someStruct);  // Standard C
void SomeStructProc(ref(SomeStruct) someStruct);     // Using Stent

Pass pointer into function (Calling function):

SomeStructProc(someStruct);  // Same for both Standard C and Stent

Vector Container

Using a similar technique to ref(T) it has been possible for libstent to provide a container implementation, similar to the functionality provided by std::vector from C++. Specifically this provides the following features.

  • Type safety
  • Zero overhead
  • Dynamic resizing
  • Safety
  • Bounds checking

Note: Even if code safety is not your primary concern, the easy to use API of this implementation can greatly simplify the codebase and save on implementation time. For this reason, we have included a standalone version (vec.h). You do not require this if you are already using stent.h as it is already provided

Creating a vector (primitives and structures):

vector(int) v = vector_new(int);
vector(struct Foo) f = vector_new(struct Foo);

Adding elements to a vector:

vector_push(v, 8);
vector_push(v, 5);
vector_push(v, 12);

Accessing the second element of a vector:

printf("%i\n", vector_at(v, 1));

Accessing the size and iterating through elements:

size_t i;
for(i = 0; i < vector_size(v); ++i) { }

Erasing two elements from a vector, starting at the second element:

vector_erase(v, 1, 2);

Cleaning up a vector:

vector_delete(v);

Convenience MACRO for iterating:

foreach(int curr, v,
  printf("%i\n", curr);
);

Leak Detector

There is also basic support for leak detection. Have a look at the src/tests/leak.c program for more information.

For a simple example, if a leak exists, a message will appear such as:

***** Memory Leak *****
Type: struct Test
File: example/leak/main.c
Line: 14

This is possible because Stent creates an "atexit" hook that upon program termination, will scan internal memory for a list of data yet to be freed.

If you have found this source code useful and would like to see more stuff like this, then please consider making a donation. It helps us justify prioritising the work required to provide free software.

Buy Me a Coffee at ko-fi.com

Contact | Legal | Bug Tracker