]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Handle top __syscall_cancel frames when getting stack traces VALGRIND_3_24_BRANCH
authorMark Wielaard <mark@klomp.org>
Sun, 30 Mar 2025 15:38:21 +0000 (17:38 +0200)
committerMark Wielaard <mark@klomp.org>
Sun, 30 Mar 2025 18:26:13 +0000 (20:26 +0200)
Since glibc 2.41 there are extra frames inserted before doing a
syscall to support proper thread cancellation.  This breaks various
suppressions and regtests involving checking syscall arguments.

Solve this by removing those extra frames from the top of the call
stack when we are processing a linux system call.

https://bugs.kde.org/show_bug.cgi?id=502126
(cherry picked from commit 41441379baa63b5471385361d08c8df317705b69)

NEWS
coregrind/m_stacktrace.c

diff --git a/NEWS b/NEWS
index 23cf88c505f00224f15ac09d088229fc6cfa9528..8b43361eb2553cb49e831e1f15222f7fb7f9fc59 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,7 @@ The following bugs have been fixed or resolved on this branch.
 498143  False positive on EVIOCGRAB ioctl
 501348  glibc built with -march=x86-64-v3 does not work due to ld.so memcmp
 501893  Missing suppression for __wcscat_avx2 (strcat-strlen-avx2.h.S:68)?
+502126  glibc 2.41 extra syscall_cancel frames
 
 To see details of a given bug, visit
   https://bugs.kde.org/show_bug.cgi?id=XXXXXX
index 630b5b87524c236106b805be643d1a65a5f70a11..0ddd3639cd8a4962f25c1afb821cabddf643eee1 100644 (file)
@@ -9,6 +9,8 @@
 
    Copyright (C) 2000-2017 Julian Seward 
       jseward@acm.org
+   Copyright (C) 2025 Mark J. Wielaard
+      mark@klomp.org
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -1598,10 +1600,59 @@ UInt VG_(get_StackTrace_with_deltas)(
                   tid, stack_highest_byte,
                   startRegs.r_pc, startRegs.r_sp);
 
-   return VG_(get_StackTrace_wrk)(tid, ips, n_ips, 
+   Int found = VG_(get_StackTrace_wrk)(tid, ips, n_ips,
                                        sps, fps,
                                        &startRegs,
                                        stack_highest_byte);
+
+#if defined(VGO_linux)
+   /* glibc might insert some extra frames before doing a syscall to support
+      thread cancellation.  This breaks various suppressions and regtests
+      involving checking syscall arguments. So when processing a syscall just
+      remove those extra frames from the top of the call stack.  */
+   if (VG_(is_in_syscall)(tid)) {
+      Int i;
+      Int start = 0;
+      DiEpoch ep = VG_(current_DiEpoch)();
+      for (i = 0; i < found; i++) {
+         /* This could be made a little more efficient by doing the lookups
+            for the symbols at glibc load time and check the address falls
+            inside the function symbol address range here. But given this
+            is only called during syscall processing, this is probably fine
+            for now.  */
+         const HChar *buf;
+         if (VG_(get_fnname_raw)(ep, ips[i], &buf)) { // raw, don't demangle
+            if (VG_STREQ("__syscall_cancel_arch", buf) ||
+                VG_STREQ("__internal_syscall_cancel", buf) ||
+#if defined(VGP_x86_linux) || defined(VGP_arm_linux)
+                VG_STREQ("__libc_do_syscall", buf) ||
+#endif
+#if defined(VGP_x86_linux)
+                VG_STREQ("_dl_sysinfo_int80", buf) ||
+#endif
+                VG_STREQ("__syscall_cancel", buf)) {
+               start++;
+               continue; // Maybe the next one is special too?
+            } else {
+               break; // Not special, only skip top stack names.
+            }
+         } else {
+            break; // No name, not special, don't skip.
+         }
+      }
+
+      if (start > 0) {
+         for (i = 0; i < (found - start); i++) {
+            ips[i] = ips[i + start];
+            if (sps) sps[i] = sps[i + start];
+            if (fps) fps[i] = fps[i + start];
+         }
+         return found - start;
+      }
+   }
+#endif
+
+   return found;
 }
 
 UInt VG_(get_StackTrace) ( ThreadId tid,