信号ハンドラーでの errno の不適切な使用
信号ハンドラーで errno を設定する関数を呼び出した後に errno を読み取る
説明
この欠陥は、信号ハンドラーで以下のいずれかの関数が呼び出された場合に発生します。
signal: 信号ハンドラーで関数signalを呼び出し、次にerrnoの値を読み取ります。たとえば、信号ハンドラー関数
handlerでsignalを呼び出し、次にerrnoを読み取るperrorを呼び出します。typedef void (*pfv)(int); void handler(int signum) { pfv old_handler = signal(signum, SIG_DFL); if (old_handler == SIG_ERR) { perror("SIGINT handler"); } }errnoを設定する POSIX® 関数: 信号ハンドラーでerrnoを設定する POSIX 関数を呼び出しても、その信号ハンドラーから返されたときにerrnoは復元されません。たとえば、信号ハンドラー関数
handlerで、errnoを変更するwaitpidを呼び出しても、返される前にerrnoは復元されません。#include <stddef.h> #include <errno.h> #include <sys/wait.h> void handler(int signum) { int rc = waitpid(-1, NULL, WNOHANG); if (ECHILD != errno) { } }
リスク
チェッカーによってフラグが設定される各ケースでは、errno の不確定の値に依存するリスクがあります。
signal:信号ハンドラーでのsignalの呼び出しに失敗した場合、errnoの値が不確定になります (C11 規格、節 7.14.1.1).errnoの特定の値に依存すると、予期しない結果になる可能性があります。errnoを設定する POSIX 関数:errnoを設定する関数は失敗時にerrnoを設定します。信号ハンドラーが呼び出されて、その信号ハンドラー自体によりerrnoを設定する関数が呼び出された後にerrnoを読み取る場合、予期しない結果になる可能性があります。
修正方法
errno の不確定の値に依存するリスクがある状況を回避します。
signal: 信号ハンドラーで関数signalを呼び出した後に、errnoを読み取ったり、errnoを読み取る関数を使用したりしないようにします。errnoを設定する POSIX 関数: 信号ハンドラーでerrnoを設定する関数を呼び出す前に、errnoを一時変数に保存します。信号ハンドラーから返される前にこの変数からerrnoを復元します。
例
結果情報
| グループ: プログラミング |
| 言語: C | C++ |
| 既定値: 手書きコードはオン、生成コードはオフ |
コマンド ライン構文: SIG_HANDLER_ERRNO_MISUSE |
| 影響度: Medium |
バージョン履歴
R2018a で導入