16

2010 年に Unix でクラッシュ時にミューテックスを自動的に解放するという質問に対するコメントで、jilles は次のように主張しました。

glibc は危険なショートカットを使用するため、glibc の堅牢なミューテックスは非常に高速です。カーネルがミューテックスを「EOWNERDEAD を引き起こす」とマークした場合、ミューテックスがまだ存在するという保証はありません。ミューテックスが破棄され、メモリーが、たまたま最後の所有スレッドの ID を適切な場所に含むメモリーマップファイルに置き換えられ、最後の所有スレッドがロックワードを書き込んだ直後に終了した場合 (ただし、ミューテックスをそのリストから完全に削除する前に)所有されているミューテックス)、ファイルが破損しています。Solaris および will-be-FreeBSD9 の堅牢なミューテックスは、このリスクを取りたくないため、低速です。

ロックが解除されていない限り (したがって、どのスレッドの堅牢なリストにも含まれていない限り)、mutex の破棄は合法ではないため、この主張を理解することはできません。また、そのようなバグ/問題を検索する参照も見つかりません。その主張は単に間違っていたのですか?

私が質問し、興味を持った理由は、これが同じ Linux の堅牢なミューテックス プリミティブに基づいて構築された私自身の実装の正確性に関連しているからです。

4

2 に答える 2

8

私はレースを見つけたと思います、そしてそれは確かに非常に醜いです. こんなふうになります:

スレッド A は堅牢なミューテックスを保持し、ロックを解除します。基本的な手順は次のとおりです。

  1. スレッドの堅牢なリスト ヘッダーの「保留」スロットに入れます。
  2. 現在のスレッドが保持する堅牢なミューテックスのリンク リストから削除します。
  3. ミューテックスのロックを解除します。
  4. スレッドの堅牢なリスト ヘッダーの「保留中」スロットをクリアします。

問題は、ステップ 3 と 4 の間で、同じプロセス内の別のスレッドがミューテックスを取得してロックを解除し、(当然のことながら) 自分がミューテックスの最終ユーザーであると信じて、破棄し、解放/マンマップする可能性があることです。その後、プロセス内のいずれかのスレッドがファイル、デバイス、または共有メモリの共有マッピングを作成し、たまたま同じアドレスが割り当てられ、その場所の値がたまたまステップ間にあるスレッドの pid と一致した場合ロック解除の 3 と 4 では、プロセスが強制終了された場合、カーネルがミューテックス所有者 ID と見なす 32 ビット整数の上位ビットを設定して、マップされたファイルを破損する状況があります。

解決策は、上記のステップ 2 と 4 の間で mmap/munmap のグローバル ロックを保持することです。これは、この質問に対する私の回答で説明されているバリアの問題に対する私の解決策とまったく同じです。

Linux で正しいフェイルセーフ プロセス共有バリアを実装できますか?

于 2012-08-17T18:34:37.700 に答える
6

FreeBSD pthread 開発者 David Xu によるレースの説明: http://lists.freebsd.org/pipermail/svn-src-user/2010-November/003668.html

レースに厳密に munmap/mmap サイクルが必要だとは思いません。共有メモリの一部は、別の用途にも使用される可能性があります。これは一般的ではありませんが有効です。

そのメッセージでも述べたように、異なる特権を持つスレッドが共通の堅牢なミューテックスにアクセスすると、より多くの「楽しみ」が生じます。所有されている堅牢なミューテックスのリストのノードはミューテックス自体にあるため、権限の低いスレッドが高い権限のスレッドのリストを破損する可能性があります。これは、高特権スレッドをクラッシュさせるために簡単に悪用される可能性があり、まれに、これにより高特権スレッドのメモリが破損する可能性があります。どうやら Linux の堅牢なミューテックスは、同じ特権を持つスレッドのみが使用できるように設計されています。これは、リンクされたリストではなく、完全にスレッドのメモリ内で堅牢なリストを配列にすることで、簡単に回避できたはずです。

于 2012-08-17T22:45:24.210 に答える