Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: moved implementation details section and modified text of CS

...

In general, I/O functions are not safe to invoke inside signal handlers. Check your system's asynchronous-safe functions before using them in signal handlers.

Implementation Details

POSIX

The following table from the the Open Group Base Specifications [Open Group 2004] defines a set of functions that are asynchronous-signal-safe. Applications may invoke these functions, without restriction, from a signal handler.

 Asynchronous-Signal-Safe Functions

_Exit()

_exit()

abort()

accept()

access()

aio_error()

aio_return()

aio_suspend()

alarm()

bind()

cfgetispeed()

cfgetospeed()

cfsetispeed()

cfsetospeed()

chdir()

chmod()

chown()

clock_gettime()

close()

connect()

creat()

dup()

dup2()

execle()

execve()

fchmod()

fchown()

fcntl()

fdatasync()

fork()

fpathconf()

fstat()

fsync()

ftruncate()

getegid()

geteuid()

getgid()

getgroups()

getpeername()

getpgrp()

getpid()

getppid()

getsockname()

getsockopt()

getuid()

kill()

link()

listen()

lseek()

lstat()

mkdir()

mkfifo()

open()

pathconf()

pause()

pipe()

poll()

posix_trace_event()

pselect()

raise()

read()

readlink()

recv()

recvfrom()

recvmsg()

rename()

rmdir()

select()

sem_post()

send()

sendmsg()

sendto()

setgid()

setpgid()

setsid()

setsockopt()

setuid()

shutdown()

sigaction()

sigaddset()

sigdelset()

sigemptyset()

sigfillset()

sigismember()

sleep()

signal()

sigpause()

sigpending()

sigprocmask()

sigqueue()

sigset()

sigsuspend()

sockatmark()

socket()

socketpair()

stat()

symlink()

sysconf()

tcdrain()

tcflow()

tcflush()

tcgetattr()

tcgetpgrp()

tcsendbreak()

tcsetattr()

tcsetpgrp()

time()

timer_getoverrun()

timer_gettime()

timer_settime()

times()

umask()

uname()

unlink()

utime()

wait()

waitpid()

write()

 

 

All functions not listed in this table are considered to be unsafe with respect to signals. In the presence of signals, all functions defined by IEEE standard 1003.1-2001 behave as defined when called from or interrupted by a signal handler, with a single exception: when a signal interrupts an unsafe function and the signal handler calls an unsafe function, the behavior is undefined.

 Note that although raise() is on the list of asynchronous-safe functions, it should not be called within a signal handler if the signal occurs as a result of abort() or raise() function.

Section 7.14.1.1, para. 4, of the C standard [ISO/IEC 9899:2011] states:

 If the signal occurs as the result of calling the abort or raise function, the signal handler shall not call the raise function.

(See also undefined behavior 131 of Annex J.)

 OpenBSD

 The OpenBSD signal() man page identifies functions that are asynchronous-signal safe. Applications may consequently invoke them, without restriction, from a signal handler. 

 The OpenBSD signal() manual page lists a few additional functions that are asynchronous-safe in OpenBSD but "probably not on other systems," including snprintf()vsnprintf(),and syslog_r()( but only when the syslog_data struct is initialized as a local variable).

Noncompliant Code Example

In this noncompliant example, the C Standard Library function fprintf() is called from the signal handler handler via the function log_message(). The function free() is  also not asynchronous-safe, and its invocation from within a signal handler is also a violation of this rule.

...

Signal handlers should be as concise as possible, ideally, unconditionally setting a flag and returning. They may also call the _Exit() function. Finally, they may call other functions provided that all implementations to which the code is ported guarantee that these functions are asynchronous-safe.This example code achieves compliance with this rule by moving the final This compliant solution sets a flag of type volatile sig_atomic_t and returns; the log_message() and call to free() outside the signal handler functions are called directly from main().

Code Block
bgColor#ccccff
langc
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

enum { MAXLINE = 1024 };
volatile sig_atomic_t eflag = 0;
char *info = NULL;

void log_message(void) {
  fprintf(stderr, info);
}

void handler(int signum) {
  eflag = 1;
}

int main(void) {
  if (signal(SIGINT, handler) == SIG_ERR) {
    /* Handle error */
  }
  info = (char*)malloc(MAXLINE);
  if (info == NULL) {
    /* Handle error */
  }

  while (!eflag) {
    /* Main loop program code */

    log_message();

    /* More program code */
  }

  log_message();
  free(info);
  info = NULL;

  return 0;
}

...

The POSIX standard is contradictory regarding raise() in signal handlers. The POSIX standard [Open Group 2004] prohibits signal handlers installed using signal() from calling the raise() function if the signal occurs as the result of calling the raise()kill()pthread_kill(), or sigqueue() functions. However, it also requires that the raise() function may be safely called within any signal handler. Consequently, it is not clear whether it is safe for POSIX applications to call raise() in signal handlers installed using signal(), but it is safe to call raise() in signal handlers installed using sigaction()

 In this non-compliant soultionsolution, the signal handlers are installed using signal() and raise() is called inside the signal handler.

Code Block
bgColor#ccccff
langc
#include <signal.h>

void log_msg(int signum) {
  /* Log error message */
}

void handler(int signum) {
  /* Do some handling specific to SIGINT */
  if (raise(SIGUSR1) != 0) { /* violation */
    /* Handle error */
  }
}

int main(void) {

  signal(SIGUSR1, log_msg);
  signal(SIGINT, handler);
   
  /* program code */
  if (raise(SIGINT) != 0) {
    /* Handle error */
  }
  /* More code */

  return 0;
}

 

Implementation Details

 

POSIX

 

The following table from the the Open Group Base Specifications [Open Group 2004] defines a set of functions that are asynchronous-signal-safe. Applications may invoke these functions, without restriction, from a signal handler.

 

 Asynchronous-Signal-Safe Functions

 

_Exit()

_exit()

abort()

accept()

access()

aio_error()

aio_return()

aio_suspend()

alarm()

bind()

cfgetispeed()

cfgetospeed()

cfsetispeed()

cfsetospeed()

chdir()

chmod()

chown()

clock_gettime()

close()

connect()

creat()

dup()

dup2()

execle()

execve()

fchmod()

fchown()

fcntl()

fdatasync()

fork()

fpathconf()

fstat()

fsync()

ftruncate()

getegid()

geteuid()

getgid()

getgroups()

getpeername()

getpgrp()

getpid()

getppid()

getsockname()

getsockopt()

getuid()

kill()

link()

listen()

lseek()

lstat()

mkdir()

mkfifo()

open()

pathconf()

pause()

pipe()

poll()

posix_trace_event()

pselect()

raise()

read()

readlink()

recv()

recvfrom()

recvmsg()

rename()

rmdir()

select()

sem_post()

send()

sendmsg()

sendto()

setgid()

setpgid()

setsid()

setsockopt()

setuid()

shutdown()

sigaction()

sigaddset()

sigdelset()

sigemptyset()

sigfillset()

sigismember()

sleep()

signal()

sigpause()

sigpending()

sigprocmask()

sigqueue()

sigset()

sigsuspend()

sockatmark()

socket()

socketpair()

stat()

symlink()

sysconf()

tcdrain()

tcflow()

tcflush()

tcgetattr()

tcgetpgrp()

tcsendbreak()

tcsetattr()

tcsetpgrp()

time()

timer_getoverrun()

timer_gettime()

timer_settime()

times()

umask()

uname()

unlink()

utime()

wait()

waitpid()

write()

 

 

 

All functions not listed in this table are considered to be unsafe with respect to signals. In the presence of signals, all functions defined by IEEE standard 1003.1-2001 behave as defined when called from or interrupted by a signal handler, with a single exception: when a signal interrupts an unsafe function and the signal handler calls an unsafe function, the behavior is undefined.

 

Note that although raise() is on the list of asynchronous-safe functions, it should not be called within a signal handler if the signal occurs as a result of abort() or raise() function.

 

Section 7.14.1.1, para. 4, of the C standard [ISO/IEC 9899:2011] states:

 

 If the signal occurs as the result of calling the abort or raise function, the signal handler shall not call the raise function.

 

(See also undefined behavior 131 of Annex J.)

 

 OpenBSD

 

 The OpenBSD signal() man page identifies functions that are asynchronous-signal safe. Applications may consequently invoke them, without restriction, from a signal handler. 

The OpenBSD signal() manual page lists a few additional functions that are asynchronous-safe in OpenBSD but "probably not on other systems," including snprintf()vsnprintf(),and syslog_r()( but only when the syslog_data struct is initialized as a local variable).


Compliant Solution (POSIX)

...