exponenta event banner

CERT C: SIG30-C правил

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

Описание

Определение правила

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

Внедрение Polyspace

Эта проверка проверяет наличие следующих проблем:

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

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

Примеры

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

Проблема

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

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

Риск

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

Зафиксировать

Стандарт 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() 

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

Пример - Вызов 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 имеет тип volatile 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;
} 
Проблема

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

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

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

Риск

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

Зафиксировать

Стандарт 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(), _Exit(), 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 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

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

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.