]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
memdebug: produce stack trace dump with libbacktrace
authorDaniel Stenberg <daniel@haxx.se>
Tue, 18 Nov 2025 13:29:09 +0000 (14:29 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 24 Nov 2025 10:58:18 +0000 (11:58 +0100)
Enable with "configure --enable-backtrace", inserts a backtrace in the
memdump log when a torture test limit is reached.

Closes #19657

configure.ac
lib/memdebug.c
tests/memanalyze.pl

index d72b33d5287bb7e5550b4a85f0db44608345ffb1..1481a096b2bc45937bc152228d649635346c88f7 100644 (file)
@@ -1108,6 +1108,22 @@ AS_HELP_STRING([--enable-libgcc],[use libgcc when linking]),
     AC_MSG_RESULT(no)
 )
 
+AC_MSG_CHECKING([whether to use libbacktrace])
+AC_ARG_WITH(backtrace,
+AS_HELP_STRING([--enable-backtrace],[use libbacktrace when linking]),
+[ case "$enableval" in
+  yes)
+    LIBS="-lbacktrace $LIBS"
+    AC_DEFINE(USE_BACKTRACE, 1, [if libbacktrace is in use])
+    AC_MSG_RESULT(yes)
+    ;;
+  *)
+    AC_MSG_RESULT(no)
+    ;;
+  esac ],
+    AC_MSG_RESULT(no)
+)
+
 CURL_CHECK_LIB_XNET
 
 dnl gethostbyname without lib or in the nsl lib?
index 758c7b6aa7e29f75a4815db6d762586eccd70c51..cbda4a2be144aa5d7258c2b626f57c8d1679e023 100644 (file)
 #include "urldata.h"
 #include "curlx/fopen.h"  /* for CURLX_FOPEN_LOW(), CURLX_FREOPEN_LOW() */
 
+#ifdef USE_BACKTRACE
+#include "backtrace.h"
+#endif
+
 /* The last 2 #include files should be in this order */
 #include "curl_memory.h"
 #include "memdebug.h"
@@ -58,6 +62,9 @@ FILE *curl_dbg_logfile = NULL;
 static bool registered_cleanup = FALSE; /* atexit registered cleanup */
 static bool memlimit = FALSE; /* enable memory limit */
 static long memsize = 0;  /* set number of mallocs allowed */
+#ifdef USE_BACKTRACE
+struct backtrace_state *btstate;
+#endif
 
 /* LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is detected
    on exit so the logfile must be closed explicitly or data could be lost.
@@ -73,6 +80,33 @@ static void curl_dbg_cleanup(void)
   }
   curl_dbg_logfile = NULL;
 }
+#ifdef USE_BACKTRACE
+static void error_callback(void *data, const char *message, int error_number)
+{
+  (void)data;
+  if(error_number == -1)
+    curl_dbg_log("compile with -g\n\n");
+  else
+    curl_dbg_log("Backtrace error %d: %s\n", error_number, message);
+}
+
+static int full_callback(void *data, uintptr_t pc, const char *pathname,
+                         int line_number, const char *function)
+{
+  (void)data;
+  (void)pc;
+  if(pathname || function || line_number)
+    curl_dbg_log("BT %s:%d -- %s\n", pathname, line_number, function);
+  return 0;
+}
+
+static void dump_bt(void)
+{
+  backtrace_full(btstate, 0, full_callback, error_callback, NULL);
+}
+#else
+#define dump_bt() /* nothing to do */
+#endif
 
 /* this sets the log filename */
 void curl_dbg_memdebug(const char *logname)
@@ -88,6 +122,9 @@ void curl_dbg_memdebug(const char *logname)
       setbuf(curl_dbg_logfile, (char *)NULL);
 #endif
   }
+#ifdef USE_BACKTRACE
+  btstate = backtrace_create_state(NULL, 0, error_callback, NULL);
+#endif
   if(!registered_cleanup)
     registered_cleanup = !atexit(curl_dbg_cleanup);
 }
@@ -115,6 +152,7 @@ static bool countcheck(const char *func, int line, const char *source)
       /* log to stderr also */
       curl_mfprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
                     source, line, func);
+      dump_bt();
       fflush(curl_dbg_logfile); /* because it might crash now */
       /* !checksrc! disable ERRNOVAR 1 */
       errno = ENOMEM;
index e35b2e7abadf98d2822f49ddb44e92956855ba7e..2b38e5e8a424389a83cffe668c61b8065399ec74 100755 (executable)
@@ -130,7 +130,10 @@ while(<$fileh>) {
     chomp $_;
     my $line = $_;
     $lnum++;
-    if($line =~ /^LIMIT ([^ ]*):(\d*) (.*)/) {
+    if($line =~ /^BT/) {
+        # back-trace, ignore
+    }
+    elsif($line =~ /^LIMIT ([^ ]*):(\d*) (.*)/) {
         # new memory limit test prefix
         my $i = $3;
         my ($source, $linenum) = ($1, $2);