bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

stack-trace: Use libasan as an alternative to libbacktrace


From: Bruno Haible
Subject: stack-trace: Use libasan as an alternative to libbacktrace
Date: Thu, 18 Jul 2024 05:02:27 +0200

This patch enables stack traces with file names and line numbers in some
situations, e.g. when using clang on Debian-based distros. (In this
situation, -lbacktrace does not work because libbacktrace.a is installed
in a GCC-private directory, but -lasan works because it is installed in
a global location.)


2024-07-17  Bruno Haible  <bruno@clisp.org>

        stack-trace: Use libasan as an alternative to libbacktrace.
        * m4/stack-trace.m4 (gl_STACK_TRACE_EARLY): As a second choice, use
        libasan.
        * lib/stack-trace-impl.h (print_stack_trace_to) [HAVE_LIBASAN]:
        Implement using libasan.
        * lib/stack-trace.c (print_stack_trace): Test also HAVE_LIBASAN.
        * lib/abort-debug.c (rpl_abort): Likewise.

diff --git a/lib/abort-debug.c b/lib/abort-debug.c
index ac5ddf15cd..2457ef07c2 100644
--- a/lib/abort-debug.c
+++ b/lib/abort-debug.c
@@ -31,7 +31,7 @@
 void
 rpl_abort (void)
 {
-#if HAVE_LIBBACKTRACE || HAVE_EXECINFO_H
+#if HAVE_LIBBACKTRACE || HAVE_LIBASAN || HAVE_EXECINFO_H
   print_stack_trace_to (stderr);
 #endif
   raise (SIGABRT);
diff --git a/lib/stack-trace-impl.h b/lib/stack-trace-impl.h
index 018563e4cc..529afad7a6 100644
--- a/lib/stack-trace-impl.h
+++ b/lib/stack-trace-impl.h
@@ -28,11 +28,33 @@ print_stack_trace_to (FILE *stream)
 {
   if (state == NULL)
     state = backtrace_create_state (NULL, 0, NULL, NULL);
-  /* Pass skip=0, to work around 
<https://github.com/ianlancetaylor/libbacktrace/issues/60>.  */
   fprintf (stream, "Stack trace:\n");
+  /* Pass skip=0, to work around 
<https://github.com/ianlancetaylor/libbacktrace/issues/60>.  */
   backtrace_print (state, 0, stream);
 }
 
+#elif HAVE_LIBASAN
+
+# include <stdio.h>
+
+/* We need only one declaration from <sanitizer/asan_interface.h>.  */
+extern
+# ifdef __cplusplus
+"C"
+# endif
+void __sanitizer_print_stack_trace (void);
+
+/* The only supported stream, in this case, is stderr.  */
+static inline void
+# if (__GNUC__ >= 3) || (__clang_major__ >= 4)
+__attribute__ ((always_inline))
+# endif
+print_stack_trace_to (FILE *stream)
+{
+  fprintf (stream, "Stack trace:\n");
+  __sanitizer_print_stack_trace ();
+}
+
 #elif HAVE_EXECINFO_H
 
 # include <stdio.h>
diff --git a/lib/stack-trace.c b/lib/stack-trace.c
index b4ad37bf78..b08a977064 100644
--- a/lib/stack-trace.c
+++ b/lib/stack-trace.c
@@ -24,7 +24,7 @@
 void
 print_stack_trace (void)
 {
-#if HAVE_LIBBACKTRACE || HAVE_EXECINFO_H
+#if HAVE_LIBBACKTRACE || HAVE_LIBASAN || HAVE_EXECINFO_H
   print_stack_trace_to (stderr);
 #endif
 }
diff --git a/m4/stack-trace.m4 b/m4/stack-trace.m4
index 7184ca7eb2..e102484e0f 100644
--- a/m4/stack-trace.m4
+++ b/m4/stack-trace.m4
@@ -1,5 +1,5 @@
 # stack-trace.m4
-# serial 1
+# serial 2
 dnl Copyright (C) 2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -48,29 +48,56 @@ AC_DEFUN([gl_STACK_TRACE_EARLY]
       CAN_PRINT_STACK_TRACE=1
       LIBS="$LIBS -lbacktrace"
     else
-      dnl The second choice is libexecinfo.
-      dnl It does not produce source file names and line numbers, only 
addresses
-      dnl (which are mostly useless due to ASLR) and _sometimes_ function 
names.
-      AC_REQUIRE([AC_CANONICAL_HOST])
-      case "$host_os" in
-        *-gnu* | gnu* | darwin* | freebsd* | dragonfly* | netbsd* | openbsd* | 
solaris*)
-          dnl execinfo might be implemented on this platform.
-          CAN_PRINT_STACK_TRACE=1
-          dnl On *BSD system, link all programs with -lexecinfo. Cf. 
m4/execinfo.m4.
-          case "$host_os" in
-            freebsd* | dragonfly* | netbsd* | openbsd*)
-              LIBS="$LIBS -lexecinfo"
-              ;;
-          esac
-          dnl Link all programs in such a way that the stack trace includes the
-          dnl function names. '-rdynamic' is equivalent to 
'-Wl,-export-dynamic'.
-          case "$host_os" in
-            *-gnu* | gnu* | openbsd*)
-              LDFLAGS="$LDFLAGS -rdynamic"
-              ;;
-          esac
-          ;;
-      esac
+      dnl The second choice is GCC's libasan, installed as part of GCC.
+      dnl It produces source file names and line numbers, if the binary
+      dnl is compiled with debug information.
+      AC_CACHE_CHECK([for libasan], [gl_cv_lib_asan], [
+        gl_saved_LIBS="$LIBS"
+        LIBS="$gl_saved_LIBS -lasan"
+        AC_LINK_IFELSE(
+          [AC_LANG_PROGRAM(
+             [[extern
+               #ifdef __cplusplus
+               "C"
+               #endif
+               void __sanitizer_print_stack_trace (void);
+             ]],
+             [[__sanitizer_print_stack_trace ();
+             ]])],
+          [gl_cv_lib_asan=yes],
+          [gl_cv_lib_asan=no])
+        LIBS="$gl_saved_LIBS"
+      ])
+      if test $gl_cv_lib_asan = yes; then
+        AC_DEFINE([HAVE_LIBASAN], [1],
+          [Define if you have the libasan library.])
+        CAN_PRINT_STACK_TRACE=1
+        LIBS="$LIBS -lasan"
+      else
+        dnl The third choice is libexecinfo.
+        dnl It does not produce source file names and line numbers, only 
addresses
+        dnl (which are mostly useless due to ASLR) and _sometimes_ function 
names.
+        AC_REQUIRE([AC_CANONICAL_HOST])
+        case "$host_os" in
+          *-gnu* | gnu* | darwin* | freebsd* | dragonfly* | netbsd* | openbsd* 
| solaris*)
+            dnl execinfo might be implemented on this platform.
+            CAN_PRINT_STACK_TRACE=1
+            dnl On *BSD system, link all programs with -lexecinfo. Cf. 
m4/execinfo.m4.
+            case "$host_os" in
+              freebsd* | dragonfly* | netbsd* | openbsd*)
+                LIBS="$LIBS -lexecinfo"
+                ;;
+            esac
+            dnl Link all programs in such a way that the stack trace includes 
the
+            dnl function names. '-rdynamic' is equivalent to 
'-Wl,-export-dynamic'.
+            case "$host_os" in
+              *-gnu* | gnu* | openbsd*)
+                LDFLAGS="$LDFLAGS -rdynamic"
+                ;;
+            esac
+            ;;
+        esac
+      fi
     fi
   fi
 ])






reply via email to

[Prev in Thread] Current Thread [Next in Thread]