public inbox for libc-help@sourceware.org
 help / color / mirror / Atom feed
From: Yubin Ruan <ablacktshirt@gmail.com>
To: "Carlos O'Donell" <carlos@redhat.com>
Cc: libc-help@sourceware.org
Subject: Re: determine whether code is running in a signal handler context
Date: Thu, 19 Oct 2017 01:52:00 -0000	[thread overview]
Message-ID: <CAJYFCiPc4ffjOKqSvf5tc5xi7tucSmBGKGyFJAGmzw=CjkCM_w@mail.gmail.com> (raw)
In-Reply-To: <a5dad2f4-0ebe-06c1-a53b-48081cb697b0@redhat.com>

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)

  reply	other threads:[~2017-10-19  1:52 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-18 14:18 Yubin Ruan
2017-10-18 18:34 ` Carlos O'Donell
2017-10-19  1:52   ` Yubin Ruan [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAJYFCiPc4ffjOKqSvf5tc5xi7tucSmBGKGyFJAGmzw=CjkCM_w@mail.gmail.com' \
    --to=ablacktshirt@gmail.com \
    --cc=carlos@redhat.com \
    --cc=libc-help@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).