extra syscall_cancel frames

Mark Wielaard mark@klomp.org
Thu Mar 20 21:21:47 GMT 2025


Hi Florian,

(Adding valgrind-developers to CC to see if someone else has some
smart ideas how to deal with this.)

On Thu, Mar 20, 2025 at 05:58:31PM +0100, Florian Weimer wrote:
> > With latest glibc on fedora rawhide (glibc-2.40.9000-37.fc43.x86_64) I
> > am seeing some extra frames in the call stack that I wonder whether to
> > specially handle in valgrind.
> >
> > Before we would report on some bad syscall argument like:
> >
> > ==1929378== Syscall param sendmsg(msg) points to uninitialised byte(s)
> > ==1929378==    at 0x4971514: sendmsg (sendmsg.c:28)
> > ==1929378==    by 0x40128B: main (sendmsg.c:46)
> > ==1929378==  Address 0x1ffefff640 is on thread 1's stack
> > ==1929378==  in frame #1, created by main (sendmsg.c:13)
> >
> > Now it looks like:
> >
> > ==2670784== Syscall param sendmsg(msg) points to uninitialised byte(s)
> > ==2670784==    at 0x48D9AE6: __internal_syscall_cancel (cancellation.c:64)
> > ==2670784==    by 0x48D9B03: __syscall_cancel (cancellation.c:75)
> > ==2670784==    by 0x49628F0: sendmsg (sendmsg.c:28)
> > ==2670784==    by 0x4005CB: main (sendmsg.c:46)
> > ==2670784==  Address 0x1ffeffff40 is on thread 1's stack
> > ==2670784==  in frame #3, created by main (sendmsg.c:13)
> >
> > Which I think is not as helpful to the user.
> > So I am wondering whether those extra frames should be handled
> > specially in valgrind and filtered out. But were these extra stack
> > frames added explicitly? And are they easily detected (symbol name
> > starting with __ and containing syscall might be a good hearistic)?
> 
> I think __internal_syscall_cancel should get inlined into
> __syscall_cancel.

It isn't, I double checked with gdb and there are always two extra
frames on top of the call stack.

> There is also another out-of-line system call in __syscall_cancel_arch,
> which you probably don't see in your example because the process is
> single-threaded.

I did indeed see that in our gdb_server testsuite, I had to filter
that out of the gdb output to make our vgdb tests pass.

> It is necessary to concentrate all cancelable system calls in one place
> for correctness reasons because we need to know if the cancelling signal
> arrives within the system call or immediately after it.  It's the only
> way to tell whether the effect of the system call has taken place or
> not.  With all system calls in one place, this is a simple address
> check.  With the previous inlining-based approach, we would have to have
> some sort of lookup table to determine whether the cancellation attempt
> happened while the system call was executing or not.
> 
> This is relevant bug:
> 
>   Race conditions in pthread cancellation
>   <https://sourceware.org/bugzilla/show_bug.cgi?id=12683>
> 
> And this commit fixed it:
> 
> commit 89b53077d2a58f00e7debdfe58afabe953dac60d
> Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> Date:   Tue Jun 25 16:17:44 2024 -0300
> 
>     nptl: Fix Race conditions in pthread cancellation [BZ#12683]

Interesting, so this is actually in 2.41? I should try the fedora 42
beta then. Do you happen to know whether people/distros have
backported this to earlier releases?

I think these extra __*syscall*cancel* frames are somewhat confusing
to the user and messes up existing suppressions. They also cause
trouble for the valgrind regtests.

I think the solution for valgrind is to just skip the top (two) frames
if they match the __*syscall*cancel* symbol address ranges. And we
only need to do that when we are creating a backtrace from a valgrind
syscall wrapper.

Looking at the glibc symtab I see four function symbol matching that
pattern:

 2140: 0000000000079840     51 FUNC    LOCAL  DEFAULT        4 __syscall_cancel_arch
 3561: 000000000006daf0     64 FUNC    LOCAL  DEFAULT        4 __syscall_cancel
 3700: 000000000006da60    140 FUNC    LOCAL  DEFAULT        4 __internal_syscall_cancel
 4566: 000000000006da00     87 FUNC    LOCAL  DEFAULT        4 __syscall_do_cancel

Can we rely on those names (and assume there are only 4) or is it
better to be flexible and just create a dynamic array for any glibc
local function that matches the __*syscall*cancel* pattern?

Thanks,

Mark


More information about the Libc-alpha mailing list