ISO/IEC TS 17961 [asyncsig]

Вызывая функции в Стандартной Библиотеке C кроме аварийного прекращения работы, _Exit, и сигнал из обработчика сигнала

Описание

Управляйте определением

Вызывая функции в Стандартной Библиотеке C кроме аварийного прекращения работы, _Exit, и сигнал из сигнала handler.[1]

Реализация Polyspace

Это средство проверки проверяет на эти проблемы:

  • Функция, вызванная от обработчика сигнала, не асинхронно-безопасного (строгий).

  • Функция, вызванная от обработчика сигнала, не асинхронно-безопасного.

Примеры

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

Проблема

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

Когда вы выбираете Функцию средства проверки, вызванную из обработчика сигнала, не асинхронно-безопасного, средство проверки обнаруживает вызовы функций, которые не асинхронно-безопасны согласно стандарту POSIX. Функция, вызванная от обработчика сигнала, не асинхронно-безопасного (строгий), не повышает дефект для этих случаев. Функция вызвала от обработчика сигнала не асинхронно-безопасные (строгие) повышения дефект для функций, которые асинхронно-безопасны согласно стандарту POSIX, но не согласно стандарту C.

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

Риск

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

Фиксация

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

  • abort()

  • _Exit()

  • quick_exit()

  • signal()

Пример - вызов raise() В обработчике сигнала
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <syslog.h>
#include <unistd.h>

void SIG_ERR_handler(int signum)
{
    int s0 = signum;
    /* SIGTERM specific handling */
}

void sig_handler(int signum)
{
    int s0 = signum;
	/* Call raise() */ 
    if (raise(SIGTERM) != 0) { 
        /* Handle error */
    }
}

int finc(void)
{
    if (signal(SIGTERM, SIG_ERR_handler) == SIG_ERR)
    {
        /* Handle error */
    }
    if (signal(SIGINT, sig_handler) == SIG_ERR)
    {
        /* Handle error */
    }
    /* Program code */
    if (raise(SIGINT) != 0)
    {
        /* Handle error */
    }
    /* More code */
    return 0;
}
        
      

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

Коррекция — удаляет вызов raise() в обработчике сигнала

Согласно стандарту C, единственными функциями, которые можно безопасно вызвать от обработчика сигнала, является abort()выход, quick_exit(), и signal().

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

void SIG_ERR_handler(int signum)
{
    int s0 = signum;
    /* SIGTERM specific handling */
}
void sig_handler(int signum)
{
    int s0 = signum;
	
  
}

int func(void)
{
    if (signal(SIGTERM, SIG_ERR_handler) == SIG_ERR)
    {
        /* Handle error */
    }
    if (signal(SIGINT, sig_handler) == SIG_ERR)
    {
        /* Handle error */
    }
    /* Program code */
    if (raise(SIGINT) != 0)
    {
        /* Handle error */
    }
    /* More code */
    return 0;
} 
Проблема

Функция, вызванная от обработчика сигнала, не асинхронно-безопасного, происходит, когда обработчик сигнала вызывает функцию, которая не асинхронно-безопасна согласно стандарту 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.

Пример - вызов printf() В обработчике сигнала
#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;
} 

Проверяйте информацию

Разрешимость: неразрешимый
Введенный в R2019a

[1]  Выписки из стандарта "Техническая характеристика ISO/IEC TS 17961 - 2013-11-15" воспроизводятся с соглашением о AFNOR. Только исходный и полный текст стандарта, как опубликовано Выпусками AFNOR - доступный через веб-сайт www.boutique.afnor.org - имеет нормативное значение.