Skip to content

Set of macros that guard against buffer overflows. Based on C99 VLA feature.

License

Notifications You must be signed in to change notification settings

skullchap/neverflow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 

Repository files navigation

neverflow.h

Small set of macros that guard against buffer overflows. Based on C99 VLA feature.

a little prologue...

Such feature of C as a variable length array (VLA) has been discussed more than once, and most of the time in a bad light. Continuous discussions on how it's dangerous and not safe, complete ban from Linux source code, ignore by Microsoft compiler and etc., led VLA as a feature to become optional since C11.

And many still miss a very important detail of this feature how it's not just being able to declare runtime arrays on stack that can blow it at any time, no. It's declaration of variably modified types.

Long story short, heres Dennnis Ritchie's paper on VLA's and this pretty informative StackOverflow answer to clarify real usage of VLAs more.

Note: keep in mind that Neverflow is not quite "battle" tested, and it's more like a pilot study of a feature at this moment.

Roughly speaking, there are two main macros to keep in mind: NEW to declare array, and AT to runtime check if index is in bounds and return address to element behind it.

// NEW(TYPE, NAME, COUNT)
// AT(NAME, IDX)

#include "neverflow.h"

int 
main(void)
{
      NEW(int, myarr, 10);      // 10 element array declaration
      int *p = AT(myarr, 4);    // pointer to 5th element
      int  v = *AT(myarr, 4);   // getting value by dereferencing
      *AT(myarr, 4) = 56;       // changing value directly by dereferencing
  
      *AT(myarr, 30) = 56;      // here comes the oopsie doopsie
      // main.c:14: Buffer Overflow. Index [30] is out of range [0-9]
      // main.c:14: Function: main
}

To semantically better distinguish getting address of element in array or element itself, GET macro was made and is a shorthand to *AT. It literally defined as

#define GET(NAME, IDX) *AT(NAME, IDX)

little things...

LET is a shorthand for __auto_type and easier type inference while mainly using AT.

LET e1 = AT(myarr, 4);  // e1 is pointer to an int
LET e2 = *AT(myarr, 4); // e2 is int

SIZE(myarr) returns size of allocated memory. DON'T USE sizeof directly on VLA without dereferencing! It will return sizeof pointer pointing to array

LEN(myarr) returns number of elements in array.

By default, Neverflow uses stdlib's calloc as an alloc function and gcc/clang feature for auto free/cleanup when array will be out of scope/block. To disable auto cleanup define NO_AUTOFREE before including neverflow.h. To use own alloc function define ALLOCF.

#define NO_AUTOFREE     // you will need to free yourself
#define ALLOCF malloc
#include "neverflow.h"

...

Passing array to function while preserving neverflow features done with ARR macro using this way:

void 
func(int count, ARR(int, arr, count))
{
      int c = LEN(arr);
      printf("ELEM COUNT: %d\n", c); // 10

      *AT(arr, 12) = 42; // fails
      // main.c:13: Buffer Overflow. Index [12] is out of range [0-9]
      // main.c:13: Function: func
}

int 
main(void)
{
      NEW(int, myarr, 10); 

      int count = LEN(myarr);
      func(count, myarr);
}

As a nice sideeffect of ARR, it's also possible to "wrap" raw pointers/arrays this way:

void 
func(int count, ARR(int, arr, count))
{
      int c = LEN(arr);
      printf("ELEM COUNT: %d\n", c);
      printf("6th elem: %d\n", GET(arr, 5)); // 42
}

int 
main(void)
{
      void *p = malloc(10 * sizeof(int));
      ARR(int, myarr, 10) = p;
      *AT(myarr, 5) = 42;
      func(LEN(myarr), myarr);
}

Changes

[0.0.3] - thanks to cornstalks from HN post for pointing out that functions passed to AT() could evaluate multiple times. AT() macro changed to statement expression to evaluate IDX once, by assigning it local idx variable.

[0.0.2] - name mangling removed, added ARR() macro to ease passing arrays to functions. Another neat sideeffect of it, is possibility of wrapping raw pointer and providing runtime bound checking.

[0.0.1] - initial release

License

MIT

About

Set of macros that guard against buffer overflows. Based on C99 VLA feature.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages