CERT C: Rule SIG30-C

Вызовите только асинхронно-безопасные функции в обработчиках сигнала

Описание

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

Вызовите только асинхронно-безопасные функции в сигнале handlers.[1]

Реализация Polyspace

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

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

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

Примеры

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

Проблема

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

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

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

Группа: правило 11. Сигналы (SIG)
Введенный в R2019a

[1]  Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ-МЕЛЛОН И/ИЛИ ЕГО ИНСТИТУТА ПРОГРАММНОЙ ИНЖЕНЕРИИ СОДЕРЖАЛ, ЗДЕСЬ ПРЕДОСТАВЛЯЕТСЯ НА БАЗИСЕ "ASIS". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ОПИСАЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.