CERT.SIG.SIG_HANDLER.SHARED_OBJ.MIGHT
シグナルハンドラー内で共有オブジェクトにアクセスしない
チェッカー CERT.SIG.SIG_HANDLER.SHARED_OBJ.MIGHT は、シグナル ハンドラー内でロックフリーであることが保証されていないアトミック型の非ローカル変数へのアクセスを検出します。
このチェッカーは、ロックフリーの動作を証明できない場合のアトミックオブジェクトに対する読み取り/書き込み時にトリガーされます。型固有の ATOMIC_*_LOCK_FREE マクロが 0 であることがわかっている場合は、基本チェッカーが CERT.SIG.SIG_HANDLER.SHARED_OBJ を報告します。
-
マクロが 1 (実装定義のロックフリー) の場合、チェッカーは atomic_is_lock_free(&var) に対するマッチング呼び出しを検出します。検出された場合、指摘は報告されません。検出されない場合は、MIGHT が報告されます。
-
マクロ値を判断できない場合、チェッカーは無難に MIGHT を報告します。
-
マクロが 2 (常時ロックフリー) の場合、指摘は報告されません。
脆弱性とリスク
シグナルハンドラー内で共有オブジェクトへのアクセスや変更を行うと、競合状態が発生し、データが不整合なままになる可能性があります。この規則の 2 つの例外 (C 規格 5.1.2.3 第 5 段落) は、ロックフリーのアトミック型オブジェクトおよび volatile sig_atomic_t 型の変数に対する読み取りおよび書き込み機能です。シグナルハンドラーから他の型のオブジェクトへのアクセスは未定義の動作です。
軽減と防止
シグナルハンドラー内では、共有オブジェクトに対するアクセスや変更を行わないでください。 そのようにする場合は、共有オブジェクトへのアクセスが以下の例外に該当することを確認してください。
-
volatile sig_atomic_t型の非ローカル変数の読み取り/書き込み -
ロックフリーの
atomic型非ローカル変数の読み取りと書き込み
脆弱コード例
#include <signal.h>
#include <stdatomic.h>
atomic_int e_flag = ATOMIC_VAR_INIT(0);
void handler(int signum) {
e_flag = 1; // CERT.SIG.SIG_HANDLER.SHARED_OBJ.MIGHT
}
int main(void) {
// If ATOMIC_INT_LOCK_FREE == 1, consider confirming at runtime:
// if (!atomic_is_lock_free(&e_flag)) { /* handle not lock-free */ }
signal(SIGINT, handler); // CERT.SIG.SIG_HANDLER.SHARED_OBJ.MIGHT
return 0;
}
アトミックタイプがロックフリーであることを確認せずに、シグナル ハンドラー内でアトミックオブジェクト (e_flag) への書き込みが行われるので、このコードには MIGHT というフラグが付けられます。
修正コード例
#include <stdatomic.h>
atomic_int e_flag = ATOMIC_VAR_INIT(0);
void handler(int signum) {
e_flag = 1; // CERT.SIG.SIG_HANDLER.SHARED_OBJ.MIGHT
}
int main(void) {
// If ATOMIC_INT_LOCK_FREE == 1, consider confirming at runtime:
if (!atomic_is_lock_free(&e_flag)) { /* handle not lock-free */ }
signal(SIGINT, handler); // CERT.SIG.SIG_HANDLER.SHARED_OBJ.MIGHT
return 0;
このコードは、atomic_is_lock_free を確認しているので、要件を満たしています。
追加の保証が必要な場合は、コンパイル時のチェックを追加して、サポートされているすべてのプラットフォームでアトミックがロックフリーに維持されることを保証してください。
#include <stdatomic.h>
atomic_int e_flag = ATOMIC_VAR_INIT(0);
// The handler doesn't do anything and is therefore compliant but not useful
void safe_handler(int signum) {};
void handler(int signum) {
e_flag = 1; // CERT.SIG.SIG_HANDLER.SHARED_OBJ.MIGHT
}
int main(void) {
#if definfed(ATOMIC_INT_LOCK_FREE) && (ATOMIC_INT_LOCK_FREE == 1)
if (!atomic_is_lock_free(&e_flag)) { signal(SIGINT, safe_handler); }
else {signal(SIGINT, handler);}
#if definfed(ATOMIC_INT_LOCK_FREE) && (ATOMIC_INT_LOCK_FREE == 2)
signal(SIGINT, handler);
#else
signal(SIGINT, safe_handler);
#endif
return 0;