On Thu, Aug 4, 2016 at 1:30 PM, Aldy Hernandez <al...@redhat.com> 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.
>      }

But how's that an issue if the chunk is created at the exact place where there
previously was an alloca?

Your class also will not work when internal_alloc is not inlined and
the alloca path
is taken like when using non-GCC host compilers.

> 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?

It looks like you want to replace _all_ alloca uses?  What's the point
in doing this
at all?  Just to be able to enable the warning during bootstrap?

Having the conditional malloc/alloca will also inhibit optimization like eliding
the malloc or alloca calls completely.

Thanks,
Richard.

> Included is the conversion of tree.c.  More to follow once we agree on a
> solution.
>
> Tested on x86-64 Linux.
>
> Aldy

Reply via email to