This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH][BZ #16159] Do not backtrace recursively.
- From: OndÅej BÃlka <neleai at seznam dot cz>
- To: libc-alpha at sourceware dot org
- Date: Thu, 14 Nov 2013 20:03:29 +0100
- Subject: [PATCH][BZ #16159] Do not backtrace recursively.
- Authentication-results: sourceware.org; auth=none
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);