Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

snprintf in signal handler creates segmentation fault if started with valgrind

This very simple C program gives me a segmentation fault when running it with valgrind. Its runs fine when started normal. It crashes when you send the USR1 signal to the process.

The problem seems to be the way snprintf handles the formatting of the float value, because it works fine if you use a string (%s) or int (%d) format parameter.

P.S. I know you you shouldn't call any printf family function inside a signal handler, but still why does it only crash with valgrind.

    #include <stdio.h>
    #include <signal.h>

    void sig_usr1(int sig) {
            char buf[128];
            snprintf(buf, sizeof(buf), "%f", 1.0);
    }

    int main(int argc, char **argv) {
            (void) signal(SIGUSR1, sig_usr1);
            while(1);
    }
like image 519
parceval Avatar asked Jul 20 '11 07:07

parceval


1 Answers

As cnicutar notes, valgrind may have an effect on anything timing related and signal handlers would certainly qualify.

I don't think snprintf is safe to use in a signal handler so it might be working in the non-valgrind case solely by accident and then valgrind comes in, changes the timing, and you get the flaming death that you were risking without valigrind.

I found a list of functions that are safe in signal handlers (according to POSIX.1-2003 ) here:

http://linux.die.net/man/2/signal

Yes, the linux.die.net man pages are a bit out of date but the list here (thanks to RedX for finding this one):

https://www.securecoding.cert.org/confluence/display/seccode/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers

doesn't mention snprintf either except in the context of OpenBSD where it say:

... asynchronous-safe in OpenBSD but "probably not on other systems," including snprintf(), ...

so the implication is that snprintf is not, in general, safe in a signal handler.

And, thanks to Nemo, we have an authoritative list of functions that are safe for use in signal handlers:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03

Start at that link and search down for _Exit and you'll see the list; then you'll see that snprintf is not on the list.

Also, I remember using write() in a signal handler because fprintf wasn't safe for a signal handler but that was a long time ago.

I don't have a copy of the relevant standard so I can't back this up with anything really authoritative but I thought I'd mention it anyway.

like image 96
mu is too short Avatar answered Sep 28 '22 15:09

mu is too short