On Thu, Dec 5, 2013 at 7:32 AM, Jakub Jelinek <ja...@redhat.com> wrote:
>
> I'm trying to understand how the backtrace_vector_* APIs are meant to work
> and used, but at least for alloc.c don't see how it can work properly:
>
> Both backtrace_vector_grow and backtrace_vector_release use
>       base = realloc (vec->base, alc);
> or
>   vec->base = realloc (vec->base, vec->size);
> (note, in the latter case it is even a memory leak if realloc fails),
> but that assumes that that vec->base has been returned by malloc/realloc
> etc.  But,
> void
> backtrace_vector_finish (struct backtrace_state *state ATTRIBUTE_UNUSED,
>                          struct backtrace_vector *vec)
> {
>   vec->base = (char *) vec->base + vec->size;
>   vec->size = 0;
> }
> will change vec->base so that it no longer is an address returned by
> malloc/realloc, so next time you call backtrace_vector_grow, if it will
> actually need to reallocate anything, it will crash in realloc or silently
> misbehave.  If this works properly in mmap.c implementation, perhaps
> backtrace_vector_finish in alloc.c should just backtrace_vector_release
> and memset (*vec, 0, sizeof (*vec)); ?

You're quite right.  That was dumb.  Thanks for noticing.  Fixed with
this patch.  Committed to mainline and 4.8 branch.

Ian

2013-12-05  Ian Lance Taylor  <i...@google.com>

        * alloc.c (backtrace_vector_finish): Add error_callback and data
        parameters.  Call backtrace_vector_release.  Return address base.
        * mmap.c (backtrace_vector_finish): Add error_callback and data
        parameters.  Return address base.
        * dwarf.c (read_function_info): Get new address base from
        backtrace_vector_finish.
        * internal.h (backtrace_vector_finish): Update declaration.
Index: dwarf.c
===================================================================
--- dwarf.c	(revision 205711)
+++ dwarf.c	(working copy)
@@ -2535,19 +2535,23 @@ read_function_info (struct backtrace_sta
   if (pfvec->count == 0)
     return;
 
-  addrs = (struct function_addrs *) pfvec->vec.base;
   addrs_count = pfvec->count;
 
   if (fvec == NULL)
     {
       if (!backtrace_vector_release (state, &lvec.vec, error_callback, data))
 	return;
+      addrs = (struct function_addrs *) pfvec->vec.base;
     }
   else
     {
       /* Finish this list of addresses, but leave the remaining space in
 	 the vector available for the next function unit.  */
-      backtrace_vector_finish (state, &fvec->vec);
+      addrs = ((struct function_addrs *)
+	       backtrace_vector_finish (state, &fvec->vec,
+					error_callback, data));
+      if (addrs == NULL)
+	return;
       fvec->count = 0;
     }
 
Index: internal.h
===================================================================
--- internal.h	(revision 205711)
+++ internal.h	(working copy)
@@ -233,13 +233,17 @@ extern void *backtrace_vector_grow (stru
 				    struct backtrace_vector *vec);
 
 /* Finish the current allocation on VEC.  Prepare to start a new
-   allocation.  The finished allocation will never be freed.  */
+   allocation.  The finished allocation will never be freed.  Returns
+   a pointer to the base of the finished entries, or NULL on
+   failure.  */
 
-extern void backtrace_vector_finish (struct backtrace_state *state,
-				     struct backtrace_vector *vec);
+extern void* backtrace_vector_finish (struct backtrace_state *state,
+				      struct backtrace_vector *vec,
+				      backtrace_error_callback error_callback,
+				      void *data);
 
-/* Release any extra space allocated for VEC.  Returns 1 on success, 0
-   on failure.  */
+/* Release any extra space allocated for VEC.  This may change
+   VEC->base.  Returns 1 on success, 0 on failure.  */
 
 extern int backtrace_vector_release (struct backtrace_state *state,
 				     struct backtrace_vector *vec,
Index: mmap.c
===================================================================
--- mmap.c	(revision 205711)
+++ mmap.c	(working copy)
@@ -230,12 +230,19 @@ backtrace_vector_grow (struct backtrace_
 
 /* Finish the current allocation on VEC.  */
 
-void
-backtrace_vector_finish (struct backtrace_state *state ATTRIBUTE_UNUSED,
-			 struct backtrace_vector *vec)
+void *
+backtrace_vector_finish (
+  struct backtrace_state *state ATTRIBUTE_UNUSED,
+  struct backtrace_vector *vec,
+  backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+  void *data ATTRIBUTE_UNUSED)
 {
+  void *ret;
+
+  ret = vec->base;
   vec->base = (char *) vec->base + vec->size;
   vec->size = 0;
+  return ret;
 }
 
 /* Release any extra space allocated for VEC.  */
Index: alloc.c
===================================================================
--- alloc.c	(revision 205711)
+++ alloc.c	(working copy)
@@ -113,12 +113,24 @@ backtrace_vector_grow (struct backtrace_
 
 /* Finish the current allocation on VEC.  */
 
-void
-backtrace_vector_finish (struct backtrace_state *state ATTRIBUTE_UNUSED,
-			 struct backtrace_vector *vec)
+void *
+backtrace_vector_finish (struct backtrace_state *state,
+			 struct backtrace_vector *vec,
+			 backtrace_error_callback error_callback,
+			 void *data)
 {
-  vec->base = (char *) vec->base + vec->size;
+  void *ret;
+
+  /* With this allocator we call realloc in backtrace_vector_grow,
+     which means we can't easily reuse the memory here.  So just
+     release it.  */
+  if (!backtrace_vector_release (state, vec, error_callback, data))
+    return NULL;
+  ret = vec->base;
+  vec->base = NULL;
   vec->size = 0;
+  vec->alc = 0;
+  return ret;
 }
 
 /* Release any extra space allocated for VEC.  */

Reply via email to