CON31-C. 他のスレッドのミューテックスをアンロックしたり破壊したりしない
ミューテックスは、同時にアクセスされる共有データ構造を保護するために使用される。ミューテックスをロックするスレッドがこのミューテックスを所有し、唯一このスレッドがミューテックスをアンロックできるスレッドでなければならない。このミューテックスがまだ使用されているうちに破壊された場合、クリティカルセクションや共有データは保護されなくなってしまう。
C 言語規格 [ISO/IEC 9899:2011] セクション 7.26.4.1 第 2 段落には次のように記載されている。
mtx_destroy
関数は、mtx
で指定されるミューテックスが使用するリソースを解放する。mtx
で指定されているミューテックスを待っているスレッドをブロックすることはできない。
これは、スレッドがミューテックスを待っている間にそのミューテックスを破壊することが未定義の動作であることを意味する。
違反コード
以下のコード例では、クリーンアップスレッドと作業スレッドの間に競合状態が存在する。クリーンアップスレッドは、もう使われていないと判断したロックを破壊する。システムに過度な負荷がかかっていると、ロックを保持していた作業スレッドは、予想よりも長く処理に時間がかかる可能性がある。作業スレッドが共有データを変更し終える前にロックが破壊されると、プログラムは予期せぬ動作を引き起こすかもしれない。
mtx_t theLock; int data; /* theLock を初期化 */ int cleanupAndFinish(void) { int result; mtx_destroy(&theLock); data++; return data; } void worker(int value) { if ((result = mtx_lock(&theLock)) == thrd_error) { /* エラー処理 */ } data += value; if ((result = mtx_unlock(&theLock)) == thrd_error) { /* エラー処理 */ } }
適合コード
以下の適合コードにおいて、ミューテックスが破壊されたあとで必要になることがない。また、ミューテックスをロックするときはエラー条件をチェックすることが重要である。
mutex_t theLock; int data; int cleanupAndFinish(void) { int result; /* ユーザが書いたアプリケーション依存の関数 */ wait_for_all_threads_to_finish(); mtx_destroy(&theLock); data++; return data; } void worker(int value) { int result; if ((result = mtx_lock(&theLock)) == thrd_error) { /* エラー処理 */ } data += value; if ((result = mtx_unlock(&theLock)) == thrd_error) { /* エラー処理 */ } }
リスク評価
ミューテックスの所有権を無視するリスクは、ミューテックスをまったく使用しないリスクと同等であり、データ完全性違反につながる可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
CON31-C |
中 |
中 |
高 |
P4 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Fortify SCA |
V. 5.0 |
|
CERT C Rule Pack を使ってこのルールの違反を検出できる。 |
関連するガイドライン
MITRE CWE | CWE-667, Insufficient locking |
参考資料
[ISO/IEC 9899:2011] | Section 7.26.4.1, "The mtx_destroy Function" |
[Open Group 2004] | pthread_mutex_lock()/pthread_mutex_unlock() pthread_mutex_destroy() |
翻訳元
これは以下のページを翻訳したものです。
CON31-C. Do not unlock or destroy another thread's mutex (revision 58)