Nat! bio photo

Nat!

Senior Mull

Twitter Github Twitch

mulle-alloca for safe stack allocations

logo

Use mulle_alloca_do like a better alloca

mulle-allocator provides the mulle_alloca_do macro for stack based storage, that gets swapped to heap based when the size exceeds a certain compile time size.

What is alloca ? Excerpts from man alloca

The alloca() function allocates size bytes of space in the stack frame of the caller. This temporary space is automatically freed the function that called alloca() returns to its caller… There is no error indication, if the stack frame cannot be extended… For certain applications, its use can improve efficiency compared to the use of malloc plus free… Otherwise, its use is discouraged…

Here is an example function, where the use of alloca avoids a malloc and free call. Getting stack space is super cheap and the automatic reclamation makes the code easier to write:

void  print_uppercase( char *s)
{
   char     *copy;
   size_t   i;
   size_t   len;

   len  = strlen( s) + 1;
   copy = alloca( len);

   for( i = 0; i < len; i++)
     copy[ i] = toupper( s[ i]);

   printf( "%s\n", copy);
}

The problems are two-fold: alloca may not be available (or is “hidden” in a non standard header, which decreases portability). The length of s is unknown and the available stack size is also unknown. So this code is likely to crash for large strings. How large ? Hard to say…

mulle_alloca_do uses a certain safe amount (the default is 128 bytes) of stack space for a temporary allocation.

Note

What is a safe amount ? The author thinks double[8] should be fine. If your system is very tiny or very large, you can set MULLE_ALLOCA_STACKSIZE to a size of your liking. Remember though, that if you call other functions that also use mulle_alloca_do the reasonable stack size is halved (and so on). Use mulle_alloca_do_flexible if you want to set the stack size per macro invocation.

But if the requests exceed this amount mulle_alloca_do will fallback to malloc/free. See above code transformed to mulle_alloca_do:

void  print_uppercase( char *s)
{
   // char     *copy;  // no longer needed, will be declared in mulle_alloca_do
   size_t   i;
   size_t   len;

   len  = strlen( s) + 1;
   mulle_alloca_do( copy, char, len) // need type to alloca for alignment
   {
      for( i = 0; i < len; i++)
        copy[ i] = toupper( s[ i]);

      printf( "%s\n", copy);
   }
}

The scope of copy is now tied to mulle_alloca_do and not the function!

/* copy not yet in scope */

mulle_alloca_do( copy, char, size)
{
   /* code block, where copy is valid */
}

/* copy no longer in scope (and freed) */

Post a comment

All comments are held for moderation; basic HTML formatting accepted.

Name:
E-mail: (not published)
Website: