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)
