protected alloca class for malloc fallback

Martin Sebor msebor@gmail.com
Fri Aug 5 02:10:00 GMT 2016


On 08/04/2016 05:30 AM, Aldy Hernandez wrote:
> Howdy!
>
> As part of my -Walloca-larger-than=life work, I've been running said
> pass over gcc, binutils, and gdb, and trying to fix things along the way.
>
> Particularly irritating and error prone is having to free malloc'd
> pointers on every function exit point.  We end up with a lot of:
>
> foo(size_t len)
> {
>    void *p, *m_p = NULL;
>    if (len < HUGE)
>      p = alloca(len);
>    else
>      p = m_p = malloc(len);
>    if (something)
>      goto out;
>    stuff();
> out:
>    free (m_p);
> }
>
> ...which nobody really likes.
>
> I've been thinking that for GCC we could have a protected_alloca class
> whose destructor frees any malloc'd memory:
>
> void foo()
> {
>    char *p;
>    protected_alloca chunk(50000);
>    p = (char *) chunk.pointer();
>    f(p);
> }
>
> This would generate:
>
> void foo() ()
> {
>    void * _3;
>
>    <bb 2>:
>    _3 = malloc (50000);
>    f (_3);
>
>    <bb 3>:
>    free (_3); [tail call]
>    return;
> }
>
> Now the problem with this is that the memory allocated by chunk is freed
> when it goes out of scope, which may not be what you want.  For example:
>
>       func()
>       {
>         char *str;
>         {
>           protected_alloca chunk (99999999);
>       // malloc'd pointer will be freed when chunk goes out of scope.
>           str = (char *) chunk.pointer ();
>         }
>         use (str);  // BAD!  Use after free.
>       }
>
> In the attached patch implementing this class I have provided another
> idiom for avoiding this problem:
>
>       func()
>       {
>         void *ptr;
>         protected_alloca chunk;
>         {
>           chunk.alloc (9999999);
>       str = (char *) chunk.pointer ();
>         }
>         // OK, pointer will be freed on function exit.
>         use (str);
>       }
>
> So I guess it's between annoying gotos and keeping track of multiple
> exit points to a function previously calling alloca, or making sure the
> protected_alloca object always resides in the scope where the memory is
> going to be used.
>
> Is there a better blessed C++ way?  If not, is this OK?

I was surprised by the always_inline trick.  I suppose it makes
sense but I wouldn't have expected to be able to rely on it.  Out
of curiosity I tested it with other compilers.  It turns out that
it only works with some like GCC and IBM XLC++, but not others
like Clang or Sun CC.  In recursive calls, they don't seem to
hold on to the memory allocated via alloca by the class ctor in
the caller.

FWIW, rather than creating a new class around alloca and putting
effort into changing code to use it I think that investing time
into replacing the function's uses with an existing C++ container
class (either GCC's own or one from the STL) might be a better
way to go.

Martin



More information about the Gcc-patches mailing list