* determine whether code is running in a signal handler context @ 2017-10-18 14:18 Yubin Ruan 2017-10-18 18:34 ` Carlos O'Donell ` (4 more replies) 0 siblings, 5 replies; 31+ messages in thread From: Yubin Ruan @ 2017-10-18 14:18 UTC (permalink / raw) To: libc-help Hi, I am writing to see if this is any util functions in libc that can help to determine it is currently running in a signal. I wrote some library and provide a function which will be used in many client code. However this function is not async-signal safe (it calls malloc(3)) so when it is called, I want to detect whether it is currently running in a signal handler. If it is, I can avoid calling those not-async-signal-safe functions which might cause deadlock. that is, I want a `in_signal_handler_context()' utility that can be used as this: int mylibfunc( void ) { if( in_signal_handler_context() ) { return(-1) } // rest of function goes here return( 0 ); } Yubin ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-18 14:18 determine whether code is running in a signal handler context Yubin Ruan @ 2017-10-18 18:34 ` Carlos O'Donell 2017-10-19 1:52 ` Yubin Ruan 2017-10-19 2:59 ` Sean Conner ` (3 subsequent siblings) 4 siblings, 1 reply; 31+ messages in thread From: Carlos O'Donell @ 2017-10-18 18:34 UTC (permalink / raw) To: Yubin Ruan, libc-help On 10/18/2017 07:18 AM, Yubin Ruan wrote: > Hi, > > I am writing to see if this is any util functions in libc that can > help to determine it is currently running in a signal. > > I wrote some library and provide a function which will be used in many > client code. However this function is not async-signal safe (it calls > malloc(3)) so when it is called, I want to detect whether it is > currently running in a signal handler. If it is, I can avoid calling > those not-async-signal-safe functions which might cause deadlock. > > that is, I want a `in_signal_handler_context()' utility that can be > used as this: > > int mylibfunc( void ) { > if( in_signal_handler_context() ) { return(-1) } > // rest of function goes here > return( 0 ); > } Only (b). (a) The kernel knows, but doesn't tell you. (b) Only via architecture-specific checks which involve inspecting the call frame to determine if there is a signal frame on the stack. (c) glibc *could* know, but it probably needs kernel help for other purposes. This issue was discussed orthogonality here: https://sourceware.org/ml/libc-alpha/2014-02/msg00798.html Where glibc would create a wrapper for all signal handlers to save and restore errno to work around bugs in signal handlers that modify errno. There is no solution yet. -- Cheers, Carlos. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-18 18:34 ` Carlos O'Donell @ 2017-10-19 1:52 ` Yubin Ruan 2017-10-19 2:19 ` Carlos O'Donell 0 siblings, 1 reply; 31+ messages in thread From: Yubin Ruan @ 2017-10-19 1:52 UTC (permalink / raw) To: Carlos O'Donell; +Cc: libc-help 2017-10-19 2:34 GMT+08:00 Carlos O'Donell <carlos@redhat.com>: > On 10/18/2017 07:18 AM, Yubin Ruan wrote: >> Hi, >> >> I am writing to see if this is any util functions in libc that can >> help to determine it is currently running in a signal. >> >> I wrote some library and provide a function which will be used in many >> client code. However this function is not async-signal safe (it calls >> malloc(3)) so when it is called, I want to detect whether it is >> currently running in a signal handler. If it is, I can avoid calling >> those not-async-signal-safe functions which might cause deadlock. >> >> that is, I want a `in_signal_handler_context()' utility that can be >> used as this: >> >> int mylibfunc( void ) { >> if( in_signal_handler_context() ) { return(-1) } >> // rest of function goes here >> return( 0 ); >> } > > Only (b). > > (a) The kernel knows, but doesn't tell you. > > (b) Only via architecture-specific checks which involve inspecting the > call frame to determine if there is a signal frame on the stack. Is (b) deterministic? How can we know whether a call frame is a signal frame and how can we know at which point we should stop when inspecting the frame? Somebody pointed out that on Linux all signal handlers are called from vdso, so I come up with the following code to "inspect" the call frame and see whether there is any address which points at some place inside the VDSO: =============================== #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <signal.h> #include <unistd.h> uintmax_t vdso_start = 0; uintmax_t vdso_end = 0; /* actually, next byte */ int check_stack_for_vdso(uint64_t rsp, size_t len) { size_t i; /* printf("rsp = %jx\n", rsp); */ for (i = 0; i < len; i++, rsp++) { /* printf("*rsp is: %jx\n", *(uint64_t *)rsp); */ if ((*(uint64_t *)rsp) >= vdso_start && (*(uint64_t *)rsp) < vdso_end) return 1; } return 0; } void handler(int signo) { uint64_t rsp; __asm__ __volatile__ ("movq %%rsp, %0" : "=r"(rsp)); /* XXX only for demonstration, don't call printf from a signal handler */ printf("handler: check_stack_for_vdso() = %d\n", check_stack_for_vdso(rsp, 200)); /* I am hoping that `check_stack_for_vdso()' here would return 1. * But that is not the case */ } void parse_maps() { FILE *maps; char buf[256]; char path[7]; uintmax_t start, end, offset, inode; char r, w, x, p; unsigned major, minor; maps = fopen("/proc/self/maps", "rt"); if (maps == NULL) return; while (!feof(maps) && !ferror(maps)) { if (fgets(buf, 256, maps) != NULL) { if (sscanf(buf, "%jx-%jx %c%c%c%c %jx %u:%u %ju %6s", &start, &end, &r, &w, &x, &p, &offset, &major, &minor, &inode, path) == 11) { if (!strcmp(path, "[vdso]")) { vdso_start = start; vdso_end = end; break; } } } } fclose(maps); printf("[vdso] at %jx-%jx\n", vdso_start, vdso_end); } int main() { struct sigaction sa; uint64_t rsp; parse_maps(); memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = handler; sa.sa_flags = SA_RESTART; if (sigaction(SIGUSR1, &sa, NULL) < 0) { perror("sigaction"); exit(1); } __asm__ __volatile__ ("movq %%rsp, %0" : "=r"(rsp)); printf("before kill: check_stack_for_vdso() = %d\n", check_stack_for_vdso(rsp, 200)); kill(getpid(), SIGUSR1); __asm__ __volatile__ ("movq %%rsp, %0" : "=r"(rsp)); printf("after kill: check_stack_for_vdso() = %d\n", check_stack_for_vdso(rsp, 200)); return 0; } ============================================== I am using a 64 bit Linux. I try to go back 200 step long when inside a signal handler, but I cannot find any address inside the vdso area. (sorry if the code above get auto-wrapped by the mail agent) Yubin [1]: https://stackoverflow.com/questions/4832743/howto-determine-if-code-is-running-in-signal-handler-context (I use some of its code) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 1:52 ` Yubin Ruan @ 2017-10-19 2:19 ` Carlos O'Donell 2017-10-19 2:39 ` Will Hawkins 2017-10-19 4:01 ` Yubin Ruan 0 siblings, 2 replies; 31+ messages in thread From: Carlos O'Donell @ 2017-10-19 2:19 UTC (permalink / raw) To: Yubin Ruan; +Cc: libc-help On 10/18/2017 06:52 PM, Yubin Ruan wrote: > 2017-10-19 2:34 GMT+08:00 Carlos O'Donell <carlos@redhat.com>: >> On 10/18/2017 07:18 AM, Yubin Ruan wrote: >>> Hi, >>> >>> I am writing to see if this is any util functions in libc that can >>> help to determine it is currently running in a signal. >>> >>> I wrote some library and provide a function which will be used in many >>> client code. However this function is not async-signal safe (it calls >>> malloc(3)) so when it is called, I want to detect whether it is >>> currently running in a signal handler. If it is, I can avoid calling >>> those not-async-signal-safe functions which might cause deadlock. >>> >>> that is, I want a `in_signal_handler_context()' utility that can be >>> used as this: >>> >>> int mylibfunc( void ) { >>> if( in_signal_handler_context() ) { return(-1) } >>> // rest of function goes here >>> return( 0 ); >>> } >> >> Only (b). >> >> (a) The kernel knows, but doesn't tell you. >> >> (b) Only via architecture-specific checks which involve inspecting the >> call frame to determine if there is a signal frame on the stack. > > Is (b) deterministic? How can we know whether a call frame is a signal > frame and how can we know at which point we should stop when > inspecting the frame? We could spend days talking about this. The answer should be deterministic, and gdb solves it, but the solution involves some heuristic checks, and unwinding (a complex topic). > Somebody pointed out that on Linux all signal handlers are called from > vdso, so I come up with the following code to "inspect" the call frame > and see whether there is any address which points at some place inside > the VDSO: This is not true. It is architecture dependent. For examples on how complex it is to get this 100% right you have to go read gdb sources to see how they do this. It is non-trivial. It might be easier to use a library like libunwind to determine this for you (if it even can). -- Cheers, Carlos. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 2:19 ` Carlos O'Donell @ 2017-10-19 2:39 ` Will Hawkins 2017-10-19 3:12 ` Carlos O'Donell 2017-10-19 4:01 ` Yubin Ruan 1 sibling, 1 reply; 31+ messages in thread From: Will Hawkins @ 2017-10-19 2:39 UTC (permalink / raw) To: Carlos O'Donell; +Cc: Yubin Ruan, libc-help On Wednesday, October 18, 2017, Carlos O'Donell <carlos@redhat.com> wrote: > On 10/18/2017 06:52 PM, Yubin Ruan wrote: > > 2017-10-19 2:34 GMT+08:00 Carlos O'Donell <carlos@redhat.com > <javascript:;>>: > >> On 10/18/2017 07:18 AM, Yubin Ruan wrote: > >>> Hi, > >>> > >>> I am writing to see if this is any util functions in libc that can > >>> help to determine it is currently running in a signal. > >>> > >>> I wrote some library and provide a function which will be used in many > >>> client code. However this function is not async-signal safe (it calls > >>> malloc(3)) so when it is called, I want to detect whether it is > >>> currently running in a signal handler. If it is, I can avoid calling > >>> those not-async-signal-safe functions which might cause deadlock. > >>> > >>> that is, I want a `in_signal_handler_context()' utility that can be > >>> used as this: > >>> > >>> int mylibfunc( void ) { > >>> if( in_signal_handler_context() ) { return(-1) } > >>> // rest of function goes here > >>> return( 0 ); > >>> } > >> > >> Only (b). > >> > >> (a) The kernel knows, but doesn't tell you. > >> > >> (b) Only via architecture-specific checks which involve inspecting the > >> call frame to determine if there is a signal frame on the stack. > > > > Is (b) deterministic? How can we know whether a call frame is a signal > > frame and how can we know at which point we should stop when > > inspecting the frame? > > We could spend days talking about this. The answer should be deterministic, > and gdb solves it, but the solution involves some heuristic checks, and > unwinding (a complex topic). > > > Somebody pointed out that on Linux all signal handlers are called from > > vdso, so I come up with the following code to "inspect" the call frame > > and see whether there is any address which points at some place inside > > the VDSO: > > This is not true. It is architecture dependent. For examples on how complex > it is to get this 100% right you have to go read gdb sources to see how > they do this. It is non-trivial. It might be easier to use a library like > libunwind to determine this for you (if it even can). This is a fascinating thread. The downside to using libunwind is that, iirc, it requires debugging information in the binary to work. In other words, it would not work on a stripped binary. Please correct me if I am wrong. Thanks for the discussion! Will > > -- > Cheers, > Carlos. > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 2:39 ` Will Hawkins @ 2017-10-19 3:12 ` Carlos O'Donell 2017-10-19 4:07 ` Yubin Ruan 2017-10-19 4:19 ` Will Hawkins 0 siblings, 2 replies; 31+ messages in thread From: Carlos O'Donell @ 2017-10-19 3:12 UTC (permalink / raw) To: Will Hawkins; +Cc: Yubin Ruan, libc-help On 10/18/2017 07:39 PM, Will Hawkins wrote: >> This is not true. It is architecture dependent. For examples on how complex >> it is to get this 100% right you have to go read gdb sources to see how >> they do this. It is non-trivial. It might be easier to use a library like >> libunwind to determine this for you (if it even can). > > This is a fascinating thread. The downside to using libunwind is that, > iirc, it requires debugging information in the binary to work. In other > words, it would not work on a stripped binary. Please correct me if I am > wrong. No. libunwind only needs .eh_frame/.debug_frame, not debug information. Some unwinders can operate without debug information, but only if the architecture, and ABI layout of the frame allow unwinding with a frame pointer. On 32-bit ARM, at least for a while, the frame pointer was synthesized by the compiler to avoid using a fixed frame pointer and free up such a pointer for the compiler to use. The side effect is that you always need the DWARF unwind information to unwind a frame, but you do *not* need debug information. One should be careful not to confuse the two. The generic term "debug information" can mean a lot more, including all the DWARF required to debug the program. You don't need this to unwind, you only need .eh_frame/.debug_frame. As you see 32-bit ARM was leading the charge here to free up a register for compiler use, and now it's common practice on x86_64 and x86 to compile without the frame pointer, and so you must have auxiliary information to unwind, and you can't write a by-hand unwinder that follows the frame pointer. The complex part is that to unwind from an asynchronously delivered signal you need asynchronous unwind tables which describe how to unwind from any point in the program, because when the signal arrives you may attempt an unwind from any point to an outer frame. Usually the unwind information can be elided to the point at which function calls are made, or try/catch blocks. But you need not unwind from the signal handler, you need only detect that you are *in* a signal handler, and libunwind might have enough heuristics for the machines you care about that it might work. I have not tried it though, so YMMV. -- Cheers, Carlos. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 3:12 ` Carlos O'Donell @ 2017-10-19 4:07 ` Yubin Ruan 2017-10-19 4:56 ` Carlos O'Donell 2017-10-19 4:19 ` Will Hawkins 1 sibling, 1 reply; 31+ messages in thread From: Yubin Ruan @ 2017-10-19 4:07 UTC (permalink / raw) To: Carlos O'Donell; +Cc: Will Hawkins, libc-help 2017-10-19 11:12 GMT+08:00 Carlos O'Donell <carlos@redhat.com>: > On 10/18/2017 07:39 PM, Will Hawkins wrote: >>> This is not true. It is architecture dependent. For examples on how complex >>> it is to get this 100% right you have to go read gdb sources to see how >>> they do this. It is non-trivial. It might be easier to use a library like >>> libunwind to determine this for you (if it even can). >> >> This is a fascinating thread. The downside to using libunwind is that, >> iirc, it requires debugging information in the binary to work. In other >> words, it would not work on a stripped binary. Please correct me if I am >> wrong. > > No. libunwind only needs .eh_frame/.debug_frame, not debug information. > > Some unwinders can operate without debug information, but only if the > architecture, and ABI layout of the frame allow unwinding with a frame > pointer. On 32-bit ARM, at least for a while, the frame pointer was > synthesized by the compiler to avoid using a fixed frame pointer and > free up such a pointer for the compiler to use. The side effect is that > you always need the DWARF unwind information to unwind a frame, but you > do *not* need debug information. One should be careful not to confuse > the two. The generic term "debug information" can mean a lot more, > including all the DWARF required to debug the program. You don't need > this to unwind, you only need .eh_frame/.debug_frame. As you see 32-bit > ARM was leading the charge here to free up a register for compiler use, > and now it's common practice on x86_64 and x86 to compile without the > frame pointer, and so you must have auxiliary information to unwind, > and you can't write a by-hand unwinder that follows the frame pointer. By "auxiliary information", do you mean those auxiliary information provided by the kernel (to the dynamic loader), e.g., environment variables, or what? It seems to me that if we have the frame pointers, it would be a lot easier. And it would be better if we limit our code to X86/64. > The complex part is that to unwind from an asynchronously delivered signal > you need asynchronous unwind tables which describe how to unwind from > any point in the program, because when the signal arrives you may attempt > an unwind from any point to an outer frame. Usually the unwind information > can be elided to the point at which function calls are made, or try/catch > blocks. Agree. That is why I think checking the stack "by hand" for addresses in VDSO is not deterministic. > But you need not unwind from the signal handler, you need only detect > that you are *in* a signal handler, and libunwind might have enough Yes. I should have emphasized that I need only detect that the code is *in* a signal handler, and that is all I want. So if anyone can provide more info/heuristic about that (just about that) I will be very thankful. Yubin > heuristics for the machines you care about that it might work. I have > not tried it though, so YMMV. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 4:07 ` Yubin Ruan @ 2017-10-19 4:56 ` Carlos O'Donell 0 siblings, 0 replies; 31+ messages in thread From: Carlos O'Donell @ 2017-10-19 4:56 UTC (permalink / raw) To: Yubin Ruan; +Cc: Will Hawkins, libc-help On 10/18/2017 09:07 PM, Yubin Ruan wrote: > By "auxiliary information", do you mean those auxiliary information > provided by the kernel (to the dynamic loader), e.g., environment > variables, or what? It seems to me that if we have the frame pointers, > it would be a lot easier. And it would be better if we limit our code > to X86/64. No, by 'auxiliary information' I mean .eh_frame/.debug_frame, the information that tells you where the current frame's data is located (on stack or in registers), so you can, from your current IP, find enough data to attempt a frame unwind. > Yes. I should have emphasized that I need only detect that the code is > *in* a signal handler, and that is all I want. So if anyone can > provide more info/heuristic about that (just about that) I will be > very thankful. You have to do architecture specific things, which I don't have immediately off the top of my head. gdb has a architecture-specific signal call recognizer: gdb/gdb/i386-linux-tdep.c: 71 /* Recognizing signal handler frames. */ 72 73 /* GNU/Linux has two flavors of signals. Normal signal handlers, and 74 "realtime" (RT) signals. The RT signals can provide additional 75 information to the signal handler if the SA_SIGINFO flag is set 76 when establishing a signal handler using `sigaction'. It is not 77 unlikely that future versions of GNU/Linux will support SA_SIGINFO 78 for normal signals too. */ ... gdb/gdb/aarch64-linux-tdep.c: 49 /* Signal frame handling. 50 51 +------------+ ^ 52 | saved lr | | 53 +->| saved fp |--+ 54 | | | 55 | | | 56 | +------------+ 57 | | saved lr | 58 +--| saved fp | 59 ^ | | 60 | | | 61 | +------------+ 62 ^ | | 63 | | signal | 64 | | | SIGTRAMP_FRAME (struct rt_sigframe) 65 | | saved regs | 66 +--| saved sp |--> interrupted_sp 67 | | saved pc |--> interrupted_pc 68 | | | 69 | +------------+ 70 | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0) 71 +--| saved fp |<- FP 72 | | NORMAL_FRAME 73 | |<- SP 74 +------------+ 75 76 On signal delivery, the kernel will create a signal handler stack 77 frame and setup the return address in LR to point at restorer stub. 78 The signal stack frame is defined by: .... And so on and so forth... -- Cheers, Carlos. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 3:12 ` Carlos O'Donell 2017-10-19 4:07 ` Yubin Ruan @ 2017-10-19 4:19 ` Will Hawkins 1 sibling, 0 replies; 31+ messages in thread From: Will Hawkins @ 2017-10-19 4:19 UTC (permalink / raw) To: Carlos O'Donell; +Cc: Yubin Ruan, libc-help On Wed, Oct 18, 2017 at 11:12 PM, Carlos O'Donell <carlos@redhat.com> wrote: > On 10/18/2017 07:39 PM, Will Hawkins wrote: >>> This is not true. It is architecture dependent. For examples on how complex >>> it is to get this 100% right you have to go read gdb sources to see how >>> they do this. It is non-trivial. It might be easier to use a library like >>> libunwind to determine this for you (if it even can). >> >> This is a fascinating thread. The downside to using libunwind is that, >> iirc, it requires debugging information in the binary to work. In other >> words, it would not work on a stripped binary. Please correct me if I am >> wrong. > > No. libunwind only needs .eh_frame/.debug_frame, not debug information. You are obviously correct. I am sorry for being misleading in my statement. I spoke broadly of debug information when that's not what I meant precisely. Thank you for your correction and the additional information that you provided. Very interesting! Will > > Some unwinders can operate without debug information, but only if the > architecture, and ABI layout of the frame allow unwinding with a frame > pointer. On 32-bit ARM, at least for a while, the frame pointer was > synthesized by the compiler to avoid using a fixed frame pointer and > free up such a pointer for the compiler to use. The side effect is that > you always need the DWARF unwind information to unwind a frame, but you > do *not* need debug information. One should be careful not to confuse > the two. The generic term "debug information" can mean a lot more, > including all the DWARF required to debug the program. You don't need > this to unwind, you only need .eh_frame/.debug_frame. As you see 32-bit > ARM was leading the charge here to free up a register for compiler use, > and now it's common practice on x86_64 and x86 to compile without the > frame pointer, and so you must have auxiliary information to unwind, > and you can't write a by-hand unwinder that follows the frame pointer. > > The complex part is that to unwind from an asynchronously delivered signal > you need asynchronous unwind tables which describe how to unwind from > any point in the program, because when the signal arrives you may attempt > an unwind from any point to an outer frame. Usually the unwind information > can be elided to the point at which function calls are made, or try/catch > blocks. > > But you need not unwind from the signal handler, you need only detect > that you are *in* a signal handler, and libunwind might have enough > heuristics for the machines you care about that it might work. I have > not tried it though, so YMMV. > > -- > Cheers, > Carlos. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 2:19 ` Carlos O'Donell 2017-10-19 2:39 ` Will Hawkins @ 2017-10-19 4:01 ` Yubin Ruan 1 sibling, 0 replies; 31+ messages in thread From: Yubin Ruan @ 2017-10-19 4:01 UTC (permalink / raw) To: Carlos O'Donell; +Cc: libc-help Hi Carlos, 2017-10-19 10:19 GMT+08:00 Carlos O'Donell <carlos@redhat.com>: > On 10/18/2017 06:52 PM, Yubin Ruan wrote: >> 2017-10-19 2:34 GMT+08:00 Carlos O'Donell <carlos@redhat.com>: >>> On 10/18/2017 07:18 AM, Yubin Ruan wrote: >>>> Hi, >>>> >>>> I am writing to see if this is any util functions in libc that can >>>> help to determine it is currently running in a signal. >>>> >>>> I wrote some library and provide a function which will be used in many >>>> client code. However this function is not async-signal safe (it calls >>>> malloc(3)) so when it is called, I want to detect whether it is >>>> currently running in a signal handler. If it is, I can avoid calling >>>> those not-async-signal-safe functions which might cause deadlock. >>>> >>>> that is, I want a `in_signal_handler_context()' utility that can be >>>> used as this: >>>> >>>> int mylibfunc( void ) { >>>> if( in_signal_handler_context() ) { return(-1) } >>>> // rest of function goes here >>>> return( 0 ); >>>> } >>> >>> Only (b). >>> >>> (a) The kernel knows, but doesn't tell you. >>> >>> (b) Only via architecture-specific checks which involve inspecting the >>> call frame to determine if there is a signal frame on the stack. >> >> Is (b) deterministic? How can we know whether a call frame is a signal >> frame and how can we know at which point we should stop when >> inspecting the frame? > > We could spend days talking about this. The answer should be deterministic, > and gdb solves it, but the solution involves some heuristic checks, and > unwinding (a complex topic). So I think I am going to talk with some gdb people some more. >> Somebody pointed out that on Linux all signal handlers are called from >> vdso, so I come up with the following code to "inspect" the call frame >> and see whether there is any address which points at some place inside >> the VDSO: > > This is not true. It is architecture dependent. For examples on how complex > it is to get this 100% right you have to go read gdb sources to see how > they do this. It is non-trivial. It might be easier to use a library like > libunwind to determine this for you (if it even can). Will it be better if we can limit the architecture to X86/64? Yubin ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-18 14:18 determine whether code is running in a signal handler context Yubin Ruan 2017-10-18 18:34 ` Carlos O'Donell @ 2017-10-19 2:59 ` Sean Conner 2017-10-19 3:12 ` Sean Conner ` (2 subsequent siblings) 4 siblings, 0 replies; 31+ messages in thread From: Sean Conner @ 2017-10-19 2:59 UTC (permalink / raw) To: libc-help It was thus said that the Great Yubin Ruan once stated: > Hi, > > I am writing to see if this is any util functions in libc that can > help to determine it is currently running in a signal. > > I wrote some library and provide a function which will be used in many > client code. However this function is not async-signal safe (it calls > malloc(3)) so when it is called, I want to detect whether it is > currently running in a signal handler. If it is, I can avoid calling > those not-async-signal-safe functions which might cause deadlock. Wouldn't it be easier to just document (in as large a font as you care to) that none of the functions in your library can be used in a signal handler, and if they are, it's "undefined behavior"? -spc ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-18 14:18 determine whether code is running in a signal handler context Yubin Ruan 2017-10-18 18:34 ` Carlos O'Donell 2017-10-19 2:59 ` Sean Conner @ 2017-10-19 3:12 ` Sean Conner 2017-10-19 3:51 ` Yubin Ruan 2017-10-20 10:32 ` Szabolcs Nagy 2017-11-27 8:43 ` Yubin Ruan 4 siblings, 1 reply; 31+ messages in thread From: Sean Conner @ 2017-10-19 3:12 UTC (permalink / raw) To: libc-help It was thus said that the Great Yubin Ruan once stated: > Hi, > > I am writing to see if this is any util functions in libc that can > help to determine it is currently running in a signal. > > I wrote some library and provide a function which will be used in many > client code. However this function is not async-signal safe (it calls > malloc(3)) so when it is called, I want to detect whether it is > currently running in a signal handler. If it is, I can avoid calling > those not-async-signal-safe functions which might cause deadlock. Wouldn't it be easier (and safer) just to document the library as not-async-signal-safe ("These functions, called from a signal handler, will invoke undefined behavior")? Use a large font if you have to, but I think protecting programmers from themselves over the long term is bad. -spc ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 3:12 ` Sean Conner @ 2017-10-19 3:51 ` Yubin Ruan 2017-10-19 7:10 ` Jeffrey Walton 0 siblings, 1 reply; 31+ messages in thread From: Yubin Ruan @ 2017-10-19 3:51 UTC (permalink / raw) To: Sean Conner; +Cc: libc-help 2017-10-19 11:12 GMT+08:00 Sean Conner <sean@conman.org>: > It was thus said that the Great Yubin Ruan once stated: >> Hi, >> >> I am writing to see if this is any util functions in libc that can >> help to determine it is currently running in a signal. >> >> I wrote some library and provide a function which will be used in many >> client code. However this function is not async-signal safe (it calls >> malloc(3)) so when it is called, I want to detect whether it is >> currently running in a signal handler. If it is, I can avoid calling >> those not-async-signal-safe functions which might cause deadlock. > > Wouldn't it be easier (and safer) just to document the library as > not-async-signal-safe ("These functions, called from a signal handler, will > invoke undefined behavior")? Use a large font if you have to, but I think > protecting programmers from themselves over the long term is bad. Yes I can document that and that is indeed an option. But I don't know whether the user will read the docs. ;-) It would be great if we can handle that smoothly such that users will not notice. Yubin ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-19 3:51 ` Yubin Ruan @ 2017-10-19 7:10 ` Jeffrey Walton 0 siblings, 0 replies; 31+ messages in thread From: Jeffrey Walton @ 2017-10-19 7:10 UTC (permalink / raw) To: Yubin Ruan; +Cc: libc-help On Wed, Oct 18, 2017 at 11:51 PM, Yubin Ruan <ablacktshirt@gmail.com> wrote: > 2017-10-19 11:12 GMT+08:00 Sean Conner <sean@conman.org>: >> ... >> Wouldn't it be easier (and safer) just to document the library as >> not-async-signal-safe ("These functions, called from a signal handler, will >> invoke undefined behavior")? Use a large font if you have to, but I think >> protecting programmers from themselves over the long term is bad. > > Yes I can document that and that is indeed an option. But I don't know > whether the user will read the docs. ;-) > > It would be great if we can handle that smoothly such that users will > not notice. If RTFM was going to work, then it would have happened in the last 50 years or so. You're applying solid engineering techniques. I encourage you to stay the course. Jeff ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-18 14:18 determine whether code is running in a signal handler context Yubin Ruan ` (2 preceding siblings ...) 2017-10-19 3:12 ` Sean Conner @ 2017-10-20 10:32 ` Szabolcs Nagy 2017-10-20 11:23 ` Yubin Ruan 2017-11-27 8:43 ` Yubin Ruan 4 siblings, 1 reply; 31+ messages in thread From: Szabolcs Nagy @ 2017-10-20 10:32 UTC (permalink / raw) To: Yubin Ruan, libc-help; +Cc: nd On 18/10/17 15:18, Yubin Ruan wrote: > Hi, > > I am writing to see if this is any util functions in libc that can > help to determine it is currently running in a signal. > > I wrote some library and provide a function which will be used in many > client code. However this function is not async-signal safe (it calls > malloc(3)) so when it is called, I want to detect whether it is > currently running in a signal handler. If it is, I can avoid calling > those not-async-signal-safe functions which might cause deadlock. > note that in posix as-safety is symmetric between the interrupted code and interrupt handler: if any of the interrupt and interrupt handler is as-safe then the behaviour is well defined. so calling non-as-safe code in an asynchronous signal handler is perfectly fine if the interrupted code is as-safe. there are synchronous signals too, i.e. raise(sig), and then the signal handler runs in well-defined state (one can use signal masks to make sure a signal handler only runs in such state) so using "in_signal_handler_context()" is not a valid way to verify the as-safety interface contract. > that is, I want a `in_signal_handler_context()' utility that can be > used as this: > > int mylibfunc( void ) { > if( in_signal_handler_context() ) { return(-1) } > // rest of function goes here > return( 0 ); > } > > > Yubin > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-20 10:32 ` Szabolcs Nagy @ 2017-10-20 11:23 ` Yubin Ruan 2017-10-20 11:31 ` Szabolcs Nagy 0 siblings, 1 reply; 31+ messages in thread From: Yubin Ruan @ 2017-10-20 11:23 UTC (permalink / raw) To: Szabolcs Nagy; +Cc: libc-help, nd Thanks Szabolcs, 2017-10-20 18:32 GMT+08:00 Szabolcs Nagy <szabolcs.nagy@arm.com>: > On 18/10/17 15:18, Yubin Ruan wrote: >> Hi, >> >> I am writing to see if this is any util functions in libc that can >> help to determine it is currently running in a signal. >> >> I wrote some library and provide a function which will be used in many >> client code. However this function is not async-signal safe (it calls >> malloc(3)) so when it is called, I want to detect whether it is >> currently running in a signal handler. If it is, I can avoid calling >> those not-async-signal-safe functions which might cause deadlock. >> > > note that in posix as-safety is symmetric between the > interrupted code and interrupt handler: if any of the > interrupt and interrupt handler is as-safe then the > behaviour is well defined. > > so calling non-as-safe code in an asynchronous signal > handler is perfectly fine if the interrupted code is > as-safe. > > there are synchronous signals too, i.e. raise(sig), > and then the signal handler runs in well-defined state > (one can use signal masks to make sure a signal handler > only runs in such state) Actually I think the point is that that piece of code should not run in a signal handler. That have nothing to do with sync-signal or async-signal code, because in both case we might encounter deadlock. From this perspective, that `in_signal_handler_context()' make sense to me. Yubin > so using "in_signal_handler_context()" is not a valid > way to verify the as-safety interface contract. > >> that is, I want a `in_signal_handler_context()' utility that can be >> used as this: >> >> int mylibfunc( void ) { >> if( in_signal_handler_context() ) { return(-1) } >> // rest of function goes here >> return( 0 ); >> } >> >> >> Yubin >> > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-20 11:23 ` Yubin Ruan @ 2017-10-20 11:31 ` Szabolcs Nagy 2017-10-20 17:19 ` Carlos O'Donell 0 siblings, 1 reply; 31+ messages in thread From: Szabolcs Nagy @ 2017-10-20 11:31 UTC (permalink / raw) To: Yubin Ruan; +Cc: nd, libc-help On 20/10/17 12:23, Yubin Ruan wrote: > Thanks Szabolcs, > > 2017-10-20 18:32 GMT+08:00 Szabolcs Nagy <szabolcs.nagy@arm.com>: >> On 18/10/17 15:18, Yubin Ruan wrote: >>> Hi, >>> >>> I am writing to see if this is any util functions in libc that can >>> help to determine it is currently running in a signal. >>> >>> I wrote some library and provide a function which will be used in many >>> client code. However this function is not async-signal safe (it calls >>> malloc(3)) so when it is called, I want to detect whether it is >>> currently running in a signal handler. If it is, I can avoid calling >>> those not-async-signal-safe functions which might cause deadlock. >>> >> >> note that in posix as-safety is symmetric between the >> interrupted code and interrupt handler: if any of the >> interrupt and interrupt handler is as-safe then the >> behaviour is well defined. >> >> so calling non-as-safe code in an asynchronous signal >> handler is perfectly fine if the interrupted code is >> as-safe. >> >> there are synchronous signals too, i.e. raise(sig), >> and then the signal handler runs in well-defined state >> (one can use signal masks to make sure a signal handler >> only runs in such state) > > Actually I think the point is that that piece of code should not run > in a signal handler. That have nothing to do with sync-signal or > async-signal code, because in both case we might encounter deadlock. > From this perspective, that `in_signal_handler_context()' make sense > to me. there is no deadlock, malloc is safe to call in a signal handler in posix if the signal interrupts as-safe code. this entire mailing list thread assumes that only as-safe code may run in a signal handler and that is wrong. your api proposal does not make sense in a posix libc. (which explains why it does not exists) (the libc startup code may raise a reserved realtime signal and make all programs run from a signal handler, it would be a posix conform implementation and your 'in_signal_handler_context' would be always true) >> so using "in_signal_handler_context()" is not a valid >> way to verify the as-safety interface contract. >> >>> that is, I want a `in_signal_handler_context()' utility that can be >>> used as this: >>> >>> int mylibfunc( void ) { >>> if( in_signal_handler_context() ) { return(-1) } >>> // rest of function goes here >>> return( 0 ); >>> } >>> >>> >>> Yubin >>> >> ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-20 11:31 ` Szabolcs Nagy @ 2017-10-20 17:19 ` Carlos O'Donell 2017-10-20 17:48 ` Szabolcs Nagy 0 siblings, 1 reply; 31+ messages in thread From: Carlos O'Donell @ 2017-10-20 17:19 UTC (permalink / raw) To: Szabolcs Nagy, Yubin Ruan; +Cc: nd, libc-help On 10/20/2017 04:31 AM, Szabolcs Nagy wrote: > On 20/10/17 12:23, Yubin Ruan wrote: >> Thanks Szabolcs, >> >> 2017-10-20 18:32 GMT+08:00 Szabolcs Nagy <szabolcs.nagy@arm.com>: >>> On 18/10/17 15:18, Yubin Ruan wrote: >>>> Hi, >>>> >>>> I am writing to see if this is any util functions in libc that can >>>> help to determine it is currently running in a signal. >>>> >>>> I wrote some library and provide a function which will be used in many >>>> client code. However this function is not async-signal safe (it calls >>>> malloc(3)) so when it is called, I want to detect whether it is >>>> currently running in a signal handler. If it is, I can avoid calling >>>> those not-async-signal-safe functions which might cause deadlock. >>>> >>> >>> note that in posix as-safety is symmetric between the >>> interrupted code and interrupt handler: if any of the >>> interrupt and interrupt handler is as-safe then the >>> behaviour is well defined. >>> >>> so calling non-as-safe code in an asynchronous signal >>> handler is perfectly fine if the interrupted code is >>> as-safe. >>> >>> there are synchronous signals too, i.e. raise(sig), >>> and then the signal handler runs in well-defined state >>> (one can use signal masks to make sure a signal handler >>> only runs in such state) >> >> Actually I think the point is that that piece of code should not run >> in a signal handler. That have nothing to do with sync-signal or >> async-signal code, because in both case we might encounter deadlock. >> From this perspective, that `in_signal_handler_context()' make sense >> to me. > > there is no deadlock, malloc is safe to call in a signal > handler in posix if the signal interrupts as-safe code. > > this entire mailing list thread assumes that only as-safe > code may run in a signal handler and that is wrong. Correct. I didn't want to go down more complex scenarios. > your api proposal does not make sense in a posix libc. > (which explains why it does not exists) > > (the libc startup code may raise a reserved realtime > signal and make all programs run from a signal handler, > it would be a posix conform implementation and your > 'in_signal_handler_context' would be always true) Conservatively, if you see you are in a signal handler, and always run AS-safe code, you are always safe. The converse is true too, if such an API call says you are *not* in a signal handler, you may always run AS-unsafe code because you know you could not have interrupted AS-unsafe code. The API could still have its uses? -- Cheers, Carlos. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-20 17:19 ` Carlos O'Donell @ 2017-10-20 17:48 ` Szabolcs Nagy 2017-10-22 6:09 ` Carlos O'Donell 0 siblings, 1 reply; 31+ messages in thread From: Szabolcs Nagy @ 2017-10-20 17:48 UTC (permalink / raw) To: Carlos O'Donell, Yubin Ruan; +Cc: nd, libc-help On 20/10/17 18:19, Carlos O'Donell wrote: > On 10/20/2017 04:31 AM, Szabolcs Nagy wrote: >> this entire mailing list thread assumes that only as-safe >> code may run in a signal handler and that is wrong. > > Correct. > > I didn't want to go down more complex scenarios. > >> your api proposal does not make sense in a posix libc. >> (which explains why it does not exists) >> > > Conservatively, if you see you are in a signal handler, > and always run AS-safe code, you are always safe. > yes, with as-safe code your are always safe. > The converse is true too, if such an API call says you are > *not* in a signal handler, you may always run AS-unsafe > code because you know you could not have interrupted > AS-unsafe code. > that is usually true but may be false: if the programmer thinks a call is as-safe when it isn't that can cause problems even if the call is not in a signal handler: int main() { register_as_unsafe_handler(); call(); // ok if as-safe, not ok if as-unsafe mask_signals(); } > The API could still have its uses? > yes it may have uses, but if a library tries to use it for sanity checks, then the false positives will cause headaches when somebody tries to use the library correctly from a signal handler. so it's a lot of complication for a not quite correct check whether as-unsafe libc api is async reentered. (e.g. a correct check would be inc/dec of a tls counter in every as-unsafe libc api on entry/exit and checking the counter, the libc could do this without a public api change, may be possible to do as an ld_preload hack if somebody really cares.. of course there are complications with callbacks and, calls that go back to libc via plt etc, but i think this can be made correct unlike the signal context check) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-20 17:48 ` Szabolcs Nagy @ 2017-10-22 6:09 ` Carlos O'Donell 2017-10-22 23:39 ` where is the definition of idtype_t supposed to live? John Lumby 2017-10-23 10:01 ` determine whether code is running in a signal handler context Szabolcs Nagy 0 siblings, 2 replies; 31+ messages in thread From: Carlos O'Donell @ 2017-10-22 6:09 UTC (permalink / raw) To: Szabolcs Nagy, Yubin Ruan; +Cc: nd, libc-help On 10/20/2017 10:48 AM, Szabolcs Nagy wrote: > On 20/10/17 18:19, Carlos O'Donell wrote: >> On 10/20/2017 04:31 AM, Szabolcs Nagy wrote: >>> this entire mailing list thread assumes that only as-safe >>> code may run in a signal handler and that is wrong. >> >> Correct. >> >> I didn't want to go down more complex scenarios. >> >>> your api proposal does not make sense in a posix libc. >>> (which explains why it does not exists) >>> >> >> Conservatively, if you see you are in a signal handler, >> and always run AS-safe code, you are always safe. >> > > yes, with as-safe code your are always safe. > >> The converse is true too, if such an API call says you are >> *not* in a signal handler, you may always run AS-unsafe >> code because you know you could not have interrupted >> AS-unsafe code. >> > > that is usually true but may be false: if the > programmer thinks a call is as-safe when it isn't > that can cause problems even if the call is not in > a signal handler: > > int main() > { > register_as_unsafe_handler(); > call(); // ok if as-safe, not ok if as-unsafe > mask_signals(); > } I don't understand this example. Could you expand on this please? >> The API could still have its uses? >> > > yes it may have uses, but if a library tries to use > it for sanity checks, then the false positives will > cause headaches when somebody tries to use the > library correctly from a signal handler. The false positive being that you run AS-safe code only, but you *could* have run AS-unsafe if you'd accurately tracked what kind of context you interrupted? In that case I would not say or use the word "correct" or "incorrect", since the code works, but it *might* conservatively require you to run AS-safe only functions. In that case it's a performance and algorithmic complexity issue. It *is* correct because you never do anything that is undefined according to the standard. > so it's a lot of complication for a not quite correct > check whether as-unsafe libc api is async reentered. It is correct, but not precise. > (e.g. a correct check would be inc/dec of a tls > counter in every as-unsafe libc api on entry/exit > and checking the counter, the libc could do this > without a public api change, may be possible to do > as an ld_preload hack if somebody really cares.. > of course there are complications with callbacks > and, calls that go back to libc via plt etc, but > i think this can be made correct unlike the signal > context check) s/correct/precise/g -- Cheers, Carlos. ^ permalink raw reply [flat|nested] 31+ messages in thread
* where is the definition of idtype_t supposed to live? 2017-10-22 6:09 ` Carlos O'Donell @ 2017-10-22 23:39 ` John Lumby 2017-10-23 13:57 ` Florian Weimer 2017-10-23 10:01 ` determine whether code is running in a signal handler context Szabolcs Nagy 1 sibling, 1 reply; 31+ messages in thread From: John Lumby @ 2017-10-22 23:39 UTC (permalink / raw) To: libc-help I recently built and installed glibc-2.24 myself and hit a problem while compiling an application which calls wait() : /usr/include/x86_64-linux-gnu/sys/wait.h:148:20: error: unknown type name ‘idtype_t’ extern int waitid (idtype_t __idtype, __id_t __id, siginfo_t *__infop, ^ After a bit of research I see that : version defined in 2.19 sys/wait.h ## where one might it expect it to live since its only reference is in here 2.21 sys/waitflags.h ## strange home as it is an enum for an input parm, not a WAITFLAG 2.24 ??? ## after a make install into an install_root, I do not see it defined anywhere under the install_root After adding the missing definition into the sys/wait.h for 2.24, all is well again. I see it is present in the sources in glibc-2.24/posix/sys/wait.h but make somehow constructed some other one : maybe related to this line evaluate-test.sh conform/XOPEN2K8/sys/wait.h ... It is more than likely I did something wrong, but I have two questions: 1. building glibc-2.24 on a "normal" linux-x86-64 system with this in config.log ../glibc-2.24/configure --with-headers=/mnt/bluebild/linux-4.8.6-NETIF_SHIELD/usr/include --prefix=/usr --enable-add-ons=libidn --enable-kernel=4.8.6 (building with gcc-5.4 if relevant, shouldn't be) where would you expect the definition for idtype_t to be in the installed system? 2. ditto for 2.26 if different (I did not try this yet) Cheers, John ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: where is the definition of idtype_t supposed to live? 2017-10-22 23:39 ` where is the definition of idtype_t supposed to live? John Lumby @ 2017-10-23 13:57 ` Florian Weimer [not found] ` <BN6PR22MB16662DE3DFB590B3D6006F81A3460@BN6PR22MB1666.namprd22.prod.outlook.com> 0 siblings, 1 reply; 31+ messages in thread From: Florian Weimer @ 2017-10-23 13:57 UTC (permalink / raw) To: John Lumby; +Cc: libc-help * John Lumby: > I recently built and installed glibc-2.24 myself and hit a problem while > compiling an application which calls wait() : > > /usr/include/x86_64-linux-gnu/sys/wait.h:148:20: error: unknown type > name ‘idtype_t’ > extern int waitid (idtype_t __idtype, __id_t __id, siginfo_t *__infop, > ^ You need to look at gcc -E output to see where the compiling is picking up the definitions. The glibc-provided header files are consistent in this regard. A possible explanation is that you installed new versions of the header files into non-multi-arch paths, and GCC does not pick them up because they are shadowed by older header files in multi-arch paths. I'm not sure if Debian ever offered to contribute the multi-arch header path changes upstream, but it's currently not possible to run ”make install” on an upstream tree and get a directory layout which is compatible with Debian and downstreams. Please avoid posting new questions to existing thread in the future. ^ permalink raw reply [flat|nested] 31+ messages in thread
[parent not found: <BN6PR22MB16662DE3DFB590B3D6006F81A3460@BN6PR22MB1666.namprd22.prod.outlook.com>]
* Re: where is the definition of idtype_t supposed to live? [not found] ` <BN6PR22MB16662DE3DFB590B3D6006F81A3460@BN6PR22MB1666.namprd22.prod.outlook.com> @ 2017-10-23 14:20 ` Florian Weimer 0 siblings, 0 replies; 31+ messages in thread From: Florian Weimer @ 2017-10-23 14:20 UTC (permalink / raw) To: John Lumby; +Cc: libc-help * John Lumby: > Thanks Florian, > > > > You need to look at gcc -E output to see where the compiling is > > picking up the definitions. > > > Yes I did that but my question was I thought pure glibc, distro-agnostic - > > after a make and make install into a install_root, where is the > definition of idtype_t supposed to be? > > (in that install_root, not in final distro layout) > > I don't think debian comes into it does it? Unless you are indicating > that make is influenced by distro choices? I checked the 2.24 sources, and glibc assumes idtype_t is defined in <sys/wait.h>. “make install” assumes the path for that is /usr/include/sys/wait.h, but that's not correct if the system uses multi-arch paths. > > Please avoid posting new questions to existing thread in the future. > > Hmm, now I see from thread index that is what happened but why? I > thought changing the subj was enough. > I did compose as reply to get the email address correct, did it > somehow base on that? Yes, changing the subject is not sufficient. Apparently, you need to start a new message from scratch in your mail client, and paste the list address into that. Please keep the thread on the mailing list. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-22 6:09 ` Carlos O'Donell 2017-10-22 23:39 ` where is the definition of idtype_t supposed to live? John Lumby @ 2017-10-23 10:01 ` Szabolcs Nagy 2017-10-23 14:30 ` Carlos O'Donell 1 sibling, 1 reply; 31+ messages in thread From: Szabolcs Nagy @ 2017-10-23 10:01 UTC (permalink / raw) To: Carlos O'Donell, Yubin Ruan; +Cc: nd, libc-help On 22/10/17 07:06, Carlos O'Donell wrote: > On 10/20/2017 10:48 AM, Szabolcs Nagy wrote: >> On 20/10/17 18:19, Carlos O'Donell wrote: >>> On 10/20/2017 04:31 AM, Szabolcs Nagy wrote: >>> The converse is true too, if such an API call says you are >>> *not* in a signal handler, you may always run AS-unsafe >>> code because you know you could not have interrupted >>> AS-unsafe code. >>> >> >> that is usually true but may be false: if the >> programmer thinks a call is as-safe when it isn't >> that can cause problems even if the call is not in >> a signal handler: >> >> int main() >> { >> register_as_unsafe_handler(); >> call(); // ok if as-safe, not ok if as-unsafe >> mask_signals(); >> } > > I don't understand this example. > > Could you expand on this please? it means that as-unsafe code may interrupt the call. (so if call is as-safe then there is no problem, otherwise there is) in practice this kind of design (where the signal handler is as-unsafe and the main code is as-safe) is very rare, but it is a valid design (e.g. think async-cancellation: the main code is as-safe, and the interrupting code is as-unsafe since it exits the thread running dtors etc). >>> The API could still have its uses? >>> >> >> yes it may have uses, but if a library tries to use >> it for sanity checks, then the false positives will >> cause headaches when somebody tries to use the >> library correctly from a signal handler. > > The false positive being that you run AS-safe code only, > but you *could* have run AS-unsafe if you'd accurately > tracked what kind of context you interrupted? > > In that case I would not say or use the word "correct" > or "incorrect", since the code works, but it *might* > conservatively require you to run AS-safe only functions. > In that case it's a performance and algorithmic complexity > issue. It *is* correct because you never do anything that > is undefined according to the standard. > ok, with the assumption that the library call is only required to be as-safe in signal handlers. >> so it's a lot of complication for a not quite correct >> check whether as-unsafe libc api is async reentered. > > It is correct, but not precise. > >> (e.g. a correct check would be inc/dec of a tls >> counter in every as-unsafe libc api on entry/exit >> and checking the counter, the libc could do this >> without a public api change, may be possible to do >> as an ld_preload hack if somebody really cares.. >> of course there are complications with callbacks >> and, calls that go back to libc via plt etc, but >> i think this can be made correct unlike the signal >> context check) > > s/correct/precise/g ok. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-23 10:01 ` determine whether code is running in a signal handler context Szabolcs Nagy @ 2017-10-23 14:30 ` Carlos O'Donell 2017-10-24 1:00 ` Yubin Ruan 0 siblings, 1 reply; 31+ messages in thread From: Carlos O'Donell @ 2017-10-23 14:30 UTC (permalink / raw) To: Szabolcs Nagy, Yubin Ruan; +Cc: nd, libc-help On 10/23/2017 03:01 AM, Szabolcs Nagy wrote: > On 22/10/17 07:06, Carlos O'Donell wrote: >> On 10/20/2017 10:48 AM, Szabolcs Nagy wrote: >>> On 20/10/17 18:19, Carlos O'Donell wrote: >>>> On 10/20/2017 04:31 AM, Szabolcs Nagy wrote: >>>> The converse is true too, if such an API call says you are >>>> *not* in a signal handler, you may always run AS-unsafe >>>> code because you know you could not have interrupted >>>> AS-unsafe code. >>>> >>> >>> that is usually true but may be false: if the >>> programmer thinks a call is as-safe when it isn't >>> that can cause problems even if the call is not in >>> a signal handler: >>> >>> int main() >>> { >>> register_as_unsafe_handler(); >>> call(); // ok if as-safe, not ok if as-unsafe >>> mask_signals(); >>> } >> >> I don't understand this example. >> >> Could you expand on this please? > > it means that as-unsafe code may interrupt the call. > (so if call is as-safe then there is no problem, > otherwise there is) Understood. Thank you for the clarification. > in practice this kind of design (where the signal handler > is as-unsafe and the main code is as-safe) is very rare, > but it is a valid design (e.g. think async-cancellation: > the main code is as-safe, and the interrupting code is > as-unsafe since it exits the thread running dtors etc). I agree completely. It is a valid design. In this case, the proposed API would force considerable added complexity. >>>> The API could still have its uses? >>>> >>> >>> yes it may have uses, but if a library tries to use >>> it for sanity checks, then the false positives will >>> cause headaches when somebody tries to use the >>> library correctly from a signal handler. >> >> The false positive being that you run AS-safe code only, >> but you *could* have run AS-unsafe if you'd accurately >> tracked what kind of context you interrupted? >> >> In that case I would not say or use the word "correct" >> or "incorrect", since the code works, but it *might* >> conservatively require you to run AS-safe only functions. >> In that case it's a performance and algorithmic complexity >> issue. It *is* correct because you never do anything that >> is undefined according to the standard. >> > > ok, with the assumption that the library call is only > required to be as-safe in signal handlers. Yes. >>> so it's a lot of complication for a not quite correct >>> check whether as-unsafe libc api is async reentered. >> >> It is correct, but not precise. >> >>> (e.g. a correct check would be inc/dec of a tls >>> counter in every as-unsafe libc api on entry/exit >>> and checking the counter, the libc could do this >>> without a public api change, may be possible to do >>> as an ld_preload hack if somebody really cares.. >>> of course there are complications with callbacks >>> and, calls that go back to libc via plt etc, but >>> i think this can be made correct unlike the signal >>> context check) >> >> s/correct/precise/g > > ok. Please forgive my pedantism. I want everyone reading this thread in the future to understand that correct in this case is about avoiding undefined behaviour e.g. interrupting an AS-unsafe context and running more AS-unsafe code. Rather than a performance/complexity issue where an API uses a heuristic that causes you to be AS-safe more often than you should. The implementation of the API we are talking about could choose to ignore the less frequently used case of AS-safe program being interrupted by an AS-unsafe handler, in order to simplify the code required to implement the API. Otherwise, as you state, you need to precisely track the context being interrupted. I think we've probably hashed out this issue to its maximum extent :-) Hopefully the original poster has had their question answered. -- Cheers, Carlos. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-23 14:30 ` Carlos O'Donell @ 2017-10-24 1:00 ` Yubin Ruan 0 siblings, 0 replies; 31+ messages in thread From: Yubin Ruan @ 2017-10-24 1:00 UTC (permalink / raw) To: Carlos O'Donell; +Cc: Szabolcs Nagy, nd, libc-help Thank you! 2017-10-23 22:30 GMT+08:00 Carlos O'Donell <carlos@redhat.com>: > On 10/23/2017 03:01 AM, Szabolcs Nagy wrote: >> On 22/10/17 07:06, Carlos O'Donell wrote: >>> On 10/20/2017 10:48 AM, Szabolcs Nagy wrote: >>>> On 20/10/17 18:19, Carlos O'Donell wrote: >>>>> On 10/20/2017 04:31 AM, Szabolcs Nagy wrote: >>>>> The converse is true too, if such an API call says you are >>>>> *not* in a signal handler, you may always run AS-unsafe >>>>> code because you know you could not have interrupted >>>>> AS-unsafe code. >>>>> >>>> >>>> that is usually true but may be false: if the >>>> programmer thinks a call is as-safe when it isn't >>>> that can cause problems even if the call is not in >>>> a signal handler: >>>> >>>> int main() >>>> { >>>> register_as_unsafe_handler(); >>>> call(); // ok if as-safe, not ok if as-unsafe >>>> mask_signals(); >>>> } >>> >>> I don't understand this example. >>> >>> Could you expand on this please? >> >> it means that as-unsafe code may interrupt the call. >> (so if call is as-safe then there is no problem, >> otherwise there is) > > Understood. Thank you for the clarification. > >> in practice this kind of design (where the signal handler >> is as-unsafe and the main code is as-safe) is very rare, >> but it is a valid design (e.g. think async-cancellation: >> the main code is as-safe, and the interrupting code is >> as-unsafe since it exits the thread running dtors etc). > > I agree completely. It is a valid design. > > In this case, the proposed API would force considerable added > complexity. > >>>>> The API could still have its uses? >>>>> >>>> >>>> yes it may have uses, but if a library tries to use >>>> it for sanity checks, then the false positives will >>>> cause headaches when somebody tries to use the >>>> library correctly from a signal handler. >>> >>> The false positive being that you run AS-safe code only, >>> but you *could* have run AS-unsafe if you'd accurately >>> tracked what kind of context you interrupted? >>> >>> In that case I would not say or use the word "correct" >>> or "incorrect", since the code works, but it *might* >>> conservatively require you to run AS-safe only functions. >>> In that case it's a performance and algorithmic complexity >>> issue. It *is* correct because you never do anything that >>> is undefined according to the standard. >>> >> >> ok, with the assumption that the library call is only >> required to be as-safe in signal handlers. > > Yes. > >>>> so it's a lot of complication for a not quite correct >>>> check whether as-unsafe libc api is async reentered. >>> >>> It is correct, but not precise. >>> >>>> (e.g. a correct check would be inc/dec of a tls >>>> counter in every as-unsafe libc api on entry/exit >>>> and checking the counter, the libc could do this >>>> without a public api change, may be possible to do >>>> as an ld_preload hack if somebody really cares.. >>>> of course there are complications with callbacks >>>> and, calls that go back to libc via plt etc, but >>>> i think this can be made correct unlike the signal >>>> context check) >>> >>> s/correct/precise/g >> >> ok. > > Please forgive my pedantism. I want everyone reading this > thread in the future to understand that correct in this case > is about avoiding undefined behaviour e.g. interrupting an > AS-unsafe context and running more AS-unsafe code. Rather than > a performance/complexity issue where an API uses a heuristic > that causes you to be AS-safe more often than you should. > > The implementation of the API we are talking about could choose > to ignore the less frequently used case of AS-safe program being > interrupted by an AS-unsafe handler, in order to simplify the > code required to implement the API. Otherwise, as you state, > you need to precisely track the context being interrupted. > > I think we've probably hashed out this issue to its maximum > extent :-) Hopefully the original poster has had their question > answered. Actually I understand all those things you discussed and I know that choosing to ignore the less frequently used case of AS-safe program being interrupted by an AS-unsafe will be a lot easier and bring less overhead. However, I just want to make the library code generic... I am still working on it and will let you know if there are any advance. Thanks, Yubin ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-10-18 14:18 determine whether code is running in a signal handler context Yubin Ruan ` (3 preceding siblings ...) 2017-10-20 10:32 ` Szabolcs Nagy @ 2017-11-27 8:43 ` Yubin Ruan 2017-11-27 11:55 ` Florian Weimer 4 siblings, 1 reply; 31+ messages in thread From: Yubin Ruan @ 2017-11-27 8:43 UTC (permalink / raw) To: libc-help; +Cc: Carlos O'Donell, Will Hawkins, spc, noloader, Szabolcs Nagy Hi friends, Still remember this thread? It turn out that determining whether or not you are currently in a signal handler is trivial with libunwind: Assume that you have build libunwind properly: ------------------------------------ #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <string.h> /* assume that you have build libunwind properly */ #include "./libunwindout/include/libunwind.h" /* Simple error handling functions */ #define handle_error_en(en, msg) \ do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) void show_backtrace(void) { unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp; unw_getcontext(&uc); unw_init_local(&cursor, &uc); while(unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); /* Upon unwinding to a signal handler, you get a "1" */ printf("Is in a signal handler [%d]\n", unw_is_signal_frame(&cursor)); printf("ip = %lx, sp = %lx \n", (long)ip, (long)sp); } } struct sigaction act; /* Upon receiving a SIGQUIT, this signal handler will be invoked */ void sighandler(int signum, siginfo_t *info, void *ptr) { printf("Received signal: %d\n", signum); printf("signal originate from pid[%d]\n", info->si_pid); printf("Inside a signal handler...\n"); show_backtrace(); while(1) ; printf("[FATAL] quiting the signal handler\n"); } int main(int argc, char *argv[]) { { printf("Pid of the current process: %d\n", getpid()); memset(&act, 0, sizeof(act)); act.sa_sigaction = sighandler; act.sa_flags = SA_SIGINFO; sigaction(SIGQUIT, &act, NULL); while(1) ; return 0; } ------------------ END ------------- So you should run this program, and then send it a SIGQUIT. Upon receiving a SIGQUIT, the signal handler will be invoked and the show_backtrace() function will be called, which will unwind the stack and eventually find the signal handler frame, reporting 1. More interesting, libunwind allows you to detect "remotely" with its libunwind-ptrace module. By "remotely", it simply means that you can use ptrace(2) to attach to a process and then you can use libunwind-ptrace to detect the remote process is running in a signal handler. For more info, please refer to libunwind's doc [1]. As of the mechanism which libunwind use, somebody refer to sigreturn(2) [2], but I still investigate in that so more material will be pending. Anyway, thank you for all your patience and discussion. [1]: http://www.nongnu.org/libunwind/docs.html [2]: https://stackoverflow.com/questions/47503630/detect-whether-tracee-is-in-a-signal-handler-when-using-ptrace/47503853 Yubin 2017-10-18 22:18 GMT+08:00 Yubin Ruan <ablacktshirt@gmail.com>: > Hi, > > I am writing to see if this is any util functions in libc that can > help to determine it is currently running in a signal. > > I wrote some library and provide a function which will be used in many > client code. However this function is not async-signal safe (it calls > malloc(3)) so when it is called, I want to detect whether it is > currently running in a signal handler. If it is, I can avoid calling > those not-async-signal-safe functions which might cause deadlock. > > that is, I want a `in_signal_handler_context()' utility that can be > used as this: > > int mylibfunc( void ) { > if( in_signal_handler_context() ) { return(-1) } > // rest of function goes here > return( 0 ); > } > > > Yubin ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-11-27 8:43 ` Yubin Ruan @ 2017-11-27 11:55 ` Florian Weimer 2017-11-27 12:50 ` Yubin Ruan 0 siblings, 1 reply; 31+ messages in thread From: Florian Weimer @ 2017-11-27 11:55 UTC (permalink / raw) To: Yubin Ruan, libc-help Cc: Carlos O'Donell, Will Hawkins, spc, noloader, Szabolcs Nagy On 11/27/2017 09:42 AM, Yubin Ruan wrote: > Still remember this thread? It turn out that determining whether or not you > are currently in a signal handler is trivial with libunwind: This is incorrect. libunwind (or any other unwinder) relies on information which is not always available. And since you need to unwind the stack completely (if not executing in a signal handler), it is very slow. Thanks, Florian ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-11-27 11:55 ` Florian Weimer @ 2017-11-27 12:50 ` Yubin Ruan 2017-11-27 12:51 ` Florian Weimer 0 siblings, 1 reply; 31+ messages in thread From: Yubin Ruan @ 2017-11-27 12:50 UTC (permalink / raw) To: Florian Weimer Cc: libc-help, Carlos O'Donell, Will Hawkins, spc, noloader, Szabolcs Nagy 2017-11-27 19:55 GMT+08:00 Florian Weimer <fweimer@redhat.com>: > On 11/27/2017 09:42 AM, Yubin Ruan wrote: >> >> Still remember this thread? It turn out that determining whether or not >> you >> are currently in a signal handler is trivial with libunwind: > > > This is incorrect. libunwind (or any other unwinder) relies on information > which is not always available. what information? > And since you need to unwind the stack > completely (if not executing in a signal handler), it is very slow. slow speed is acceptable though. Yubin ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-11-27 12:50 ` Yubin Ruan @ 2017-11-27 12:51 ` Florian Weimer 2017-11-27 12:58 ` Adhemerval Zanella 0 siblings, 1 reply; 31+ messages in thread From: Florian Weimer @ 2017-11-27 12:51 UTC (permalink / raw) To: Yubin Ruan Cc: libc-help, Carlos O'Donell, Will Hawkins, spc, noloader, Szabolcs Nagy On 11/27/2017 01:50 PM, Yubin Ruan wrote: > 2017-11-27 19:55 GMT+08:00 Florian Weimer <fweimer@redhat.com>: >> On 11/27/2017 09:42 AM, Yubin Ruan wrote: >>> >>> Still remember this thread? It turn out that determining whether or not >>> you >>> are currently in a signal handler is trivial with libunwind: >> >> >> This is incorrect. libunwind (or any other unwinder) relies on information >> which is not always available. > > what information? Unwind tables. A correct stack pointer or frame pointer. Florian ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: determine whether code is running in a signal handler context 2017-11-27 12:51 ` Florian Weimer @ 2017-11-27 12:58 ` Adhemerval Zanella 0 siblings, 0 replies; 31+ messages in thread From: Adhemerval Zanella @ 2017-11-27 12:58 UTC (permalink / raw) To: libc-help On 27/11/2017 10:51, Florian Weimer wrote: > On 11/27/2017 01:50 PM, Yubin Ruan wrote: >> 2017-11-27 19:55 GMT+08:00 Florian Weimer <fweimer@redhat.com>: >>> On 11/27/2017 09:42 AM, Yubin Ruan wrote: >>>> >>>> Still remember this thread? It turn out that determining whether or not >>>> you >>>> are currently in a signal handler is trivial with libunwind: >>> >>> >>> This is incorrect. libunwind (or any other unwinder) relies on information >>> which is not always available. >> >> what information? > > Unwind tables. A correct stack pointer or frame pointer. > > Florian Just check libunwind usage and implementation for unw_is_signal_frame and you will notice a lot of ad-hoc and heuristics which may or not fail depending of the underlying system and binary. Also unw_is_signal_frame is not implemented for all architectures or for all OS, it is hardly a portable interface to rely on. ^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2017-11-27 12:58 UTC | newest] Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-10-18 14:18 determine whether code is running in a signal handler context Yubin Ruan 2017-10-18 18:34 ` Carlos O'Donell 2017-10-19 1:52 ` Yubin Ruan 2017-10-19 2:19 ` Carlos O'Donell 2017-10-19 2:39 ` Will Hawkins 2017-10-19 3:12 ` Carlos O'Donell 2017-10-19 4:07 ` Yubin Ruan 2017-10-19 4:56 ` Carlos O'Donell 2017-10-19 4:19 ` Will Hawkins 2017-10-19 4:01 ` Yubin Ruan 2017-10-19 2:59 ` Sean Conner 2017-10-19 3:12 ` Sean Conner 2017-10-19 3:51 ` Yubin Ruan 2017-10-19 7:10 ` Jeffrey Walton 2017-10-20 10:32 ` Szabolcs Nagy 2017-10-20 11:23 ` Yubin Ruan 2017-10-20 11:31 ` Szabolcs Nagy 2017-10-20 17:19 ` Carlos O'Donell 2017-10-20 17:48 ` Szabolcs Nagy 2017-10-22 6:09 ` Carlos O'Donell 2017-10-22 23:39 ` where is the definition of idtype_t supposed to live? John Lumby 2017-10-23 13:57 ` Florian Weimer [not found] ` <BN6PR22MB16662DE3DFB590B3D6006F81A3460@BN6PR22MB1666.namprd22.prod.outlook.com> 2017-10-23 14:20 ` Florian Weimer 2017-10-23 10:01 ` determine whether code is running in a signal handler context Szabolcs Nagy 2017-10-23 14:30 ` Carlos O'Donell 2017-10-24 1:00 ` Yubin Ruan 2017-11-27 8:43 ` Yubin Ruan 2017-11-27 11:55 ` Florian Weimer 2017-11-27 12:50 ` Yubin Ruan 2017-11-27 12:51 ` Florian Weimer 2017-11-27 12:58 ` Adhemerval Zanella
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).