Function called from signal handler not asynchronous-safe

Вызовите к неопределенному поведению программы причин прерванной функции

Описание

Этот дефект происходит, когда обработчик сигнала вызывает функцию, которая не асинхронно-безопасна согласно стандарту POSIX. Асинхронно-безопасная функция может быть прервана в любой точке в ее выполнении, затем названном снова, не вызывая противоречивое состояние. Это может также правильно обработать глобальные данные, которые могут быть в противоречивом состоянии.

Если обработчик сигнала вызывает другую функцию, которая вызывает асинхронно-небезопасную функцию, дефект появляется на вызове функции в обработчике сигнала. Дефект traceback показывает полный путь от обработчика сигнала до асинхронно-небезопасной функции.

Риск

Когда обработчик сигнала вызывается, осуществление программы прервано. После того, как обработчик закончен, резюме выполнения программы при прерывании. Если функция выполняется во время прерывания, вызывание его из обработчика сигнала является неопределенным поведением, если это не асинхронно-безопасно.

Фиксация

Стандарт POSIX задает эти функции как асинхронно-безопасные. Можно вызвать эти функции от обработчика сигнала.

_exit()getpgrp()setsockopt()
_Exit()getpid()setuid()
abort()getppid()shutdown()
accept()getsockname()sigaction()
access()getsockopt()sigaddset()
aio_error()getuid()sigdelset()
aio_return()kill()sigemptyset()
aio_suspend()link()sigfillset()
alarm()linkat()sigismember()
bind()listen()signal()
cfgetispeed()lseek()sigpause()
cfgetospeed()lstat()sigpending()
cfsetispeed()mkdir()sigprocmask()
cfsetospeed()mkdirat()sigqueue()
chdir()mkfifo()sigset()
chmod()mkfifoat()sigsuspend()
chown()mknod()sleep()
clock_gettime()mknodat()sockatmark()
close()open()socket()
connect()openat()socketpair()
creat()pathconf()stat()
dup()pause()symlink()
dup2()pipe()symlinkat()
execl()poll()sysconf()
execle()posix_trace_event()tcdrain()
execv()pselect()tcflow()
execve()pthread_kill()tcflush()
faccessat()pthread_self()tcgetattr()
fchdir()pthread_sigmask()tcgetpgrp()
fchmod()quick_exit()tcsendbreak()
fchmodat()raise()tcsetattr()
fchown()read()tcsetpgrp()
fchownat()readlink()time()
fcntl()readlinkat()timer_getoverrun()
fdatasync()recv()timer_gettime()
fexecve()recvfrom()timer_settime()
fork()recvmsg()times()
fpathconf()rename()umask()
fstat()renameat()uname()
fstatat()rmdir()unlink()
fsync()select()unlinkat()
ftruncate()sem_post()utime()
futimens()send()utimensat()
getegid()sendmsg()utimes()
geteuid()sendto()wait()
getgid()setgid()waitpid()
getgroups()setpgid()write()
getpeername()setsid() 

Функции не в предыдущей таблице не асинхронно-безопасны, и не должны быть вызваны от сигнала hander.

Примеры

развернуть все

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <syslog.h>
#include <unistd.h>

#define SIZE20 20

extern volatile sig_atomic_t e_flag;

void display_info(const char *info)
{
    if (info)
    {
        (void)fputs(info, stderr);
    }
}

void sig_handler(int signum)
{
    /* Call function printf() that is not
	asynchronous-safe */
	printf("signal %d received.", signum); 
    e_flag = 1;
}

int main(void)
{
    e_flag = 0;
    if (signal(SIGINT, sig_handler) == SIG_ERR)
    {
        /* Handle error */
    }
    char *info = (char *)calloc(SIZE20, sizeof(char));
    if (info == NULL)
    {
        /* Handle Error */
    }
    while (!e_flag)
    {
        /* Main loop program code */
        display_info(info);
        /* More program code */
    }
    free(info);
    info = NULL;
    return 0;
}
        
      

В этом примере, sig_handler вызовы printf() при ловле сигнала. Если обработчик отлавливает другой сигнал в то время как printf() выполняется, поведение программы не определено.

Коррекция — флаг набора только в обработчике сигнала

Используйте свой обработчик сигнала, чтобы установить только значение флага. e_flag имеет тип энергозависимый sig_atomic_t. sig_handler может безопасно получить доступ к нему асинхронно.

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <syslog.h>
#include <unistd.h>

#define SIZE20 20

extern volatile sig_atomic_t e_flag;

void display_info(const char *info)
{
    if (info)
    {
        (void)fputs(info, stderr);
    }
}

void sig_handler1(int signum)
{
    int s0 = signum;
    e_flag = 1;       
}

int func(void)
{
    e_flag = 0;
    if (signal(SIGINT, sig_handler1) == SIG_ERR)
    {
        /* Handle error */
    }
    char *info = (char *)calloc(SIZE20, 1);
    if (info == NULL)
    {
        /* Handle error */
    }
    while (!e_flag)
    {
        /* Main loop program code */
        display_info(info);
        /* More program code */
    }
    free(info);
    info = NULL;
    return 0;
} 

Информация о результате

Группа: Программирование
Язык: C | C++
Значение по умолчанию: Off
Синтаксис командной строки: SIG_HANDLER_ASYNC_UNSAFE
Удар: Средняя
ID CWE: 364, 387, 413, 479, 663, 828
Введенный в R2017b