This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][BZ #16159] Do not backtrace recursively.


Hi,

This bug has a simple solution but with some performance overhead.

A problem is that backtrace calls dlopen which calls malloc which could
call backtrace again.

A solution is detect that backtrace was recursed and return empty one to
break recursion.

There is a memory cost in one extra thread local variable. With a
reentrant implementation of ptread_lock_mutex_cnt from other thread I
could do this without tls.

A generic solution would be to make __libc_once return 1 when recursive
invocation is detected and change its uses to return appropriate error
value.

Also to make writing async-signal-safe programs easier we could add a
extension function pthread_once_r which returns error on recursive
invocation from same thread.


./ChangeLog:

	* sysdeps/i386/backtrace.c (__backtrace): Return empty backtrace
	when invoked recursively. 
	* sysdeps/s390/s390-32/backtrace.c (__backtrace): Likewise.
	* sysdeps/s390/s390-64/backtrace.c (__backtrace): Likewise.
	* sysdeps/sparc/backtrace.c (__backtrace): Likewise.
	* sysdeps/x86_64/backtrace.c (__backtrace): Likewise.

./ports/ChangeLog.m68k:

	* sysdeps/m68k/backtrace.c (__backtrace): Return empty backtrace
	when invoked recursively.

./ports/ChangeLog.arm:

	* sysdeps/arm/backtrace.c (__backtrace): Return empty backtrace
	when invoked recursively.

diff --git a/ports/sysdeps/arm/backtrace.c b/ports/sysdeps/arm/backtrace.c
index e627d71..218c053 100644
--- a/ports/sysdeps/arm/backtrace.c
+++ b/ports/sysdeps/arm/backtrace.c
@@ -91,14 +91,23 @@ __backtrace (array, size)
      void **array;
      int size;
 {
+  static __thread int recursed = 0;
+  if (recursed)
+    return 0;
+  recursed = 1;
+
   struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
 #ifdef SHARED
   __libc_once_define (static, once);
 
   __libc_once (once, init);
   if (unwind_backtrace == NULL)
-    return 0;
+    {
+      recursed = 0;
+      return 0;
+    }
 #endif
+  recursed = 0;
 
   if (size >= 1)
     unwind_backtrace (backtrace_helper, &arg);
diff --git a/ports/sysdeps/m68k/backtrace.c b/ports/sysdeps/m68k/backtrace.c
index decd03c..037ab2a 100644
--- a/ports/sysdeps/m68k/backtrace.c
+++ b/ports/sysdeps/m68k/backtrace.c
@@ -110,15 +110,26 @@ struct layout
 int
 __backtrace (void **array, int size)
 {
+  static __thread int recursed = 0;
+  if (recursed)
+    return 0;
+  recursed = 1;
+
+
   struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
 #ifdef SHARED
   __libc_once_define (static, once);
 
   __libc_once (once, init);
   if (unwind_backtrace == NULL)
-    return 0;
+    {
+      recursed = 0;
+      return 0;
+    }
 #endif
- 
+  recursed = 0;
+
   if (size >= 1)
     unwind_backtrace (backtrace_helper, &arg);
 
diff --git a/sysdeps/i386/backtrace.c b/sysdeps/i386/backtrace.c
index 7b801b2..f3a3897 100644
--- a/sysdeps/i386/backtrace.c
+++ b/sysdeps/i386/backtrace.c
@@ -113,14 +113,23 @@ __backtrace (array, size)
      void **array;
      int size;
 {
+  static __thread int recursed = 0;
+  if (recursed)
+    return 0;
+  recursed = 1;
+
   struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
 #ifdef SHARED
   __libc_once_define (static, once);
 
   __libc_once (once, init);
   if (unwind_backtrace == NULL)
-    return 0;
+    {
+      recursed = 0;
+      return 0;
+    }
 #endif
+  recursed = 0;
 
   if (size >= 1)
     unwind_backtrace (backtrace_helper, &arg);
diff --git a/sysdeps/s390/s390-32/backtrace.c b/sysdeps/s390/s390-32/backtrace.c
index 042efb4..e8ac385 100644
--- a/sysdeps/s390/s390-32/backtrace.c
+++ b/sysdeps/s390/s390-32/backtrace.c
@@ -125,12 +125,20 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
 int
 __backtrace (void **array, int size)
 {
+  static __thread int recursed = 0;
+  if (recursed)
+    return 0;
+  recursed = 1;
+
   struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
 #ifdef SHARED
   __libc_once_define (static, once);
 
   __libc_once (once, init);
 #endif
+  recursed = 0;
+
   if (unwind_backtrace == NULL)
     return __backchain_backtrace (array, size);
 
diff --git a/sysdeps/s390/s390-64/backtrace.c b/sysdeps/s390/s390-64/backtrace.c
index 60f3271..6214ed9 100644
--- a/sysdeps/s390/s390-64/backtrace.c
+++ b/sysdeps/s390/s390-64/backtrace.c
@@ -124,12 +124,19 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
 int
 __backtrace (void **array, int size)
 {
+  static __thread int recursed = 0;
+  if (recursed)
+    return 0;
+  recursed = 1;
+
   struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
 #ifdef SHARED
   __libc_once_define (static, once);
 
   __libc_once (once, init);
 #endif
+  recursed = 0;
+
   if (unwind_backtrace == NULL)
     return __backchain_backtrace (array, size);
 
diff --git a/sysdeps/sparc/backtrace.c b/sysdeps/sparc/backtrace.c
index 48f3cf6..56e9d25 100644
--- a/sysdeps/sparc/backtrace.c
+++ b/sysdeps/sparc/backtrace.c
@@ -104,6 +104,7 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
 int
 __backtrace (void **array, int size)
 {
   struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
   bool use_unwinder;
   int count;
@@ -111,6 +112,10 @@ __backtrace (void **array, int size)
   if (!size)
     return 0;
 
+  static __thread int recursed = 0;
+  if (recursed)
+    return 0;
+  recursed = 1;
   use_unwinder = true;
 #ifdef SHARED
   __libc_once_define (static, once);
@@ -119,7 +124,7 @@ __backtrace (void **array, int size)
   if (unwind_backtrace == NULL)
     use_unwinder = false;
 #endif
+  recursed = 0;
   if (use_unwinder == false)
     {
       struct layout *current;
diff --git a/sysdeps/x86_64/backtrace.c b/sysdeps/x86_64/backtrace.c
index c09a591..acf2063 100644
--- a/sysdeps/x86_64/backtrace.c
+++ b/sysdeps/x86_64/backtrace.c
@@ -96,14 +96,22 @@ __backtrace (array, size)
      void **array;
      int size;
 {
+  static __thread int recursed = 0;
+  if (recursed)
+    return 0;
+  recursed = 1;
   struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
 #ifdef SHARED
   __libc_once_define (static, once);
 
   __libc_once (once, init);
   if (unwind_backtrace == NULL)
-    return 0;
+    {
+      recursed = 0;
+      return 0;
+    }
 #endif
+  recursed = 0;
 
   if (size >= 1)
     unwind_backtrace (backtrace_helper, &arg);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]