fix null pointer in mtrace

Message ID 1573550539-34259-1-git-send-email-liusirui@huawei.com
State Superseded
Headers show
Series
  • fix null pointer in mtrace
Related show

Commit Message

Liusirui Nov. 12, 2019, 9:22 a.m.
In a multi-threaded program, some threads request or free memory and try to write trace info
into file which "mallstream" points to. At the same time, another thread calls "muntrace" and
set "mallstream" to NULL. This may cause a segmentation fault.

The comment in malloc/mtrace.c says "We could be printing a NULL here; that's OK.". Although
the functions mtrace/muntrace are used for debugging, program isn't expected to crash while using
these functions.

---
 malloc/mtrace.c | 29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

-- 
2.7.4

Comments

liqingqing Nov. 12, 2019, 9:39 a.m. | #1
On 2019/11/12 17:22, Liusirui wrote:
> In a multi-threaded program, some threads request or free memory and try to write trace info

> into file which "mallstream" points to. At the same time, another thread calls "muntrace" and

> set "mallstream" to NULL. This may cause a segmentation fault.

> 

> The comment in malloc/mtrace.c says "We could be printing a NULL here; that's OK.". Although

> the functions mtrace/muntrace are used for debugging, program isn't expected to crash while using

> these functions.

> 

> ---

>  malloc/mtrace.c | 29 ++++++++++++++++-------------

>  1 file changed, 16 insertions(+), 13 deletions(-)

> 

> diff --git a/malloc/mtrace.c b/malloc/mtrace.c

> index 707f998..33f01b4 100644

> --- a/malloc/mtrace.c

> +++ b/malloc/mtrace.c

> @@ -44,6 +44,10 @@

>  

>  #define TRACE_BUFFER_SIZE 512

>  

> +#define mtrace_print(file, format, ...) do { \

> +if (file != NULL) mtrace_print(file, format,##__VA_ARGS__); \

> +} while(0)

> +


I had tested this scenario, it seems like that the fprintf and other file operation function do not check the invalid argument like the null pointer.
does any one knows why fprintf do not check the input? thanks
Florian Weimer Nov. 12, 2019, 10:41 a.m. | #2
* liqingqing:

> I had tested this scenario, it seems like that the fprintf and other

> file operation function do not check the invalid argument like the

> null pointer.  does any one knows why fprintf do not check the input?


It's not required by the standard because violating preconditions
results in undefined behavior.  Sloppily written code with such bugs
tends to not check error returns from functions, either.  This means if
we added a null check for the stream argument to fprintf (e.g., failing
with EINVAL in that case), it would only obscure the problem and make
diagnosis even more difficult.

Thanks,
Florian
liqingqing Nov. 13, 2019, 1:28 a.m. | #3
On 2019/11/12 18:41, Florian Weimer wrote:
> * liqingqing:

> 

>> I had tested this scenario, it seems like that the fprintf and other

>> file operation function do not check the invalid argument like the

>> null pointer.  does any one knows why fprintf do not check the input?

> 

> It's not required by the standard because violating preconditions

> results in undefined behavior.  Sloppily written code with such bugs

> tends to not check error returns from functions, either.  This means if

> we added a null check for the stream argument to fprintf (e.g., failing

> with EINVAL in that case), it would only obscure the problem and make

> diagnosis even more difficult.

> 

> Thanks,

> Florian

> 

clear, thank you Florian

Patch

diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index 707f998..33f01b4 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -44,6 +44,10 @@ 
 
 #define TRACE_BUFFER_SIZE 512
 
+#define mtrace_print(file, format, ...) do { \
+if (file != NULL) mtrace_print(file, format,##__VA_ARGS__); \
+} while(0)
+
 static FILE *mallstream;
 static const char mallenv[] = "MALLOC_TRACE";
 static char *malloc_trace_buffer;
@@ -99,12 +103,12 @@  tr_where (const void *caller, Dl_info *info)
                         ")");
             }
 
-          fprintf (mallstream, "@ %s%s%s[%p] ",
+          mtrace_print (mallstream, "@ %s%s%s[%p] ",
                    info->dli_fname ? : "", info->dli_fname ? ":" : "",
                    buf, caller);
         }
       else
-        fprintf (mallstream, "@ [%p] ", caller);
+        mtrace_print (mallstream, "@ [%p] ", caller);
     }
 }
 
@@ -166,7 +170,7 @@  tr_freehook (void *ptr, const void *caller)
   Dl_info *info = lock_and_info (caller, &mem);
   tr_where (caller, info);
   /* Be sure to print it first.  */
-  fprintf (mallstream, "- %p\n", ptr);
+  mtrace_print (mallstream, "- %p\n", ptr);
   if (ptr == mallwatch)
     {
       __libc_lock_unlock (lock);
@@ -198,8 +202,7 @@  tr_mallochook (size_t size, const void *caller)
   set_trace_hooks ();
 
   tr_where (caller, info);
-  /* We could be printing a NULL here; that's OK.  */
-  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
+  mtrace_print (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
 
   __libc_lock_unlock (lock);
 
@@ -232,17 +235,17 @@  tr_reallochook (void *ptr, size_t size, const void *caller)
     {
       if (size != 0)
         /* Failed realloc.  */
-        fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
+        mtrace_print (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
       else
-        fprintf (mallstream, "- %p\n", ptr);
+        mtrace_print (mallstream, "- %p\n", ptr);
     }
   else if (ptr == NULL)
-    fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
+    mtrace_print (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
   else
     {
-      fprintf (mallstream, "< %p\n", ptr);
+      mtrace_print (mallstream, "< %p\n", ptr);
       tr_where (caller, info);
-      fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
+      mtrace_print (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
     }
 
   __libc_lock_unlock (lock);
@@ -270,7 +273,7 @@  tr_memalignhook (size_t alignment, size_t size, const void *caller)
 
   tr_where (caller, info);
   /* We could be printing a NULL here; that's OK.  */
-  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
+  mtrace_print (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
 
   __libc_lock_unlock (lock);
 
@@ -333,7 +336,7 @@  mtrace (void)
           /* Be sure it doesn't malloc its buffer!  */
           malloc_trace_buffer = mtb;
           setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
-          fprintf (mallstream, "= Start\n");
+          mtrace_print (mallstream, "= Start\n");
 	  save_default_hooks ();
 	  set_trace_hooks ();
 #ifdef _LIBC
@@ -363,6 +366,6 @@  muntrace (void)
   mallstream = NULL;
   set_default_hooks ();
 
-  fprintf (f, "= End\n");
+  mtrace_print (f, "= End\n");
   fclose (f);
 }