9

まず、私が説明している問題がどのように、そしてなぜ起こるかを理解していると言わせてください。私はコンピュータ サイエンスを専攻しており、オーバーフロー/アンダーフローと符号付き/符号なしの算術演算を理解しています。(このトピックに慣れていない人のために、Apple のセキュア コーディング ガイドでは、整数オーバーフローについて簡単に説明しています。)

私の質問は、そのようなエラーが検出された後の報告と回復についてです。より具体的には、Objective-C フレームワークの場合です。(私はCHDataStructuresを作成して維持しています。) オブジェクトを格納するためのメモリを割り当て、必要に応じて動的に拡張するコレクション クラスがいくつかあります。オーバーフローに関連するクラッシュはまだ見たことがありません。これはおそらく、私のテスト ケースでほとんど正常なデータが使用されているためです。ただし、検証されていない値が与えられると、物事はかなり急速に爆発する可能性があり、それを防ぎたい.

これが発生する一般的なケースを少なくとも2 つ特定しました。

  1. 呼び出し元が、非常に大きな符号なし値 (または負の符号付き値) を に渡します-initWithCapacity:
  2. 容量を動的に拡張するのに十分な数のオブジェクトが追加され、容量がオーバーフローを引き起こすほど大きくなりました。

簡単な部分は、オーバーフローが発生するかどうかを検出することです。(たとえば、length * sizeof(void*)バイトを割り当てようとする前にlength <= UINT_MAX / sizeof(void*)、このテストに失敗すると、製品がオーバーフローし、必要なよりもはるかに小さいメモリ領域が割り当てられる可能性があることを意味するため、チェックすることができます。それをサポートするプラットフォームでは、checkint.h APIは別の選択肢があります。) より難しい部分は、それを適切に処理する方法を決定することです。最初のシナリオでは、発信者の方が障害に対処するための準備が整っている (または少なくとも考え方が整っている) 可能性があります。2 番目のシナリオは、オブジェクトがコレクションに追加されるコード内の任意の場所で発生する可能性があり、これはまったく決定論的ではない可能性があります。

それでは、私の質問は次のとおりです。このような状況で整数オーバーフローが発生した場合、「善良な市民」Objective-C コードはどのように動作すると予想されますか? (理想的には、私のプロジェクトは Cocoa の Foundation と同じ精神のフレームワークであるため、最大の「インピーダンス マッチング」のために動作する方法をモデル化したいと考えています。私が見つけた Apple のドキュメントでは、これについてはすべてです。) いずれにせよ、エラーを報告することは当然のことだと思います。オブジェクトを追加する API (シナリオ 2 を引き起こす可能性があります) はエラー パラメーターを受け入れないため、問題を解決するために実際に何ができるでしょうか? そのような状況で本当に大丈夫と考えられるのは何ですか?もっとうまくやれるなら、故意にクラッシュしやすいコードを書くのは嫌です...

4

5 に答える 5

4

ログに記録して例外を発生させます。

エンドユーザーではなく、他のプログラマーにとって本当に良い市民になることしかできないので、問題を2階に渡し、何が起こっているのか、何が問題なのか (数値を与える)、どこで発生しているのかを明確に説明してください。根本原因を取り除くことができます。

于 2010-03-07T06:03:05.837 に答える
3

動的に拡大するアレイベースのストレージに関しては、できることは限られています。私はスーパーコンピューター用の Moab スケジューラーの開発者です。数千のプロセッサー、数千のジョブ、および大量のジョブ出力を備えた非常に多数のシステムも扱っています。ある時点で、UINT_MAX や LONG_LONG_MAX などよりも大きなサイズを処理するためにまったく新しいデータ型を作成せずに、バッファーをこれ以上大きく宣言することはできません。この時点で、ほとんどの「通常の」マシンではとにかくスタック/ヒープスペースが不足しています。したがって、意味のあるエラーメッセージをログに記録し、コレクションが爆発しないようにします。ユーザーがCHDataStructuresコレクションに多くのものを追加する必要がある場合は、非常に大きな数を扱う問題があることを知っておく必要があります.

もう 1 つの可能性は、unsigned int または unsigned long を使用してより大きな配列を割り当てることができない場合に、配列ベースのストレージを動的に割り当てられるリンク リスト ベースのストレージに変換することです。これにはコストがかかりますが、フレームワークのユーザーにとってそれほど気にならないほどまれにしか発生しません。動的に割り当てられたリンクリストベースのコレクションのサイズの制限はヒープのサイズであるため、コレクションに「オーバーフロー」するのに十分なアイテムを追加したユーザーは、アイテムがあったかどうかよりも大きな問題を抱えています。正常に追加されました。

于 2010-02-12T06:50:23.383 に答える
3

次の 2 つの問題があります。

(1) 割り当てが失敗し、メモリが不足しています。

(2) 続行すると (1) につながるオーバーフローまたはその他の誤った状態が検出されました。

(1)の場合、あなたはうんざりしています(失敗した割り当てが両方ともばかげていて、失敗した割り当てがその1つだけであることがわかっている場合を除きます)。これが発生した場合、あなたができる最善のことは、できるだけ早くクラッシュし、できるだけ多くの証拠を残すことです. abort()特に、のような名前を呼び出す関数を作成するとIAmCrashingOnPurposeBecauseYourMemoryIsDepleted()、クラッシュ ログに証拠が残ります。

それが本当に (2) である場合、追加の質問があります。具体的には、その状況から回復できますか? また、ユーザーのデータはそのまま残っていますか? 回復できる場合は、壮大な...そうすれば、ユーザーは知る必要がありません。そうでない場合は、ユーザーのデータが破損していないことを完全に確認する必要があります。そうでない場合は、保存して死にます。ユーザーのデータが破損している場合は、破損したデータを保持しないように最善を尽くし、何かがひどく間違っていることをユーザーに知らせてください。ユーザーのデータが既に永続化されているが、破損している場合は... うーん... ああ... 何らかの回復ツールの作成を検討することをお勧めします。

于 2010-03-11T03:39:23.030 に答える
1

Cocoa コレクションと同じことをするのが正しいと思います。たとえば、次のコードがあるとします。

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSMutableArray * a = [[NSMutableArray alloc] init];

    for (uint32_t i = 0; i < ULONG_MAX; ++i) {
        for (uint32_t i = 0; i < 10000000; ++i) {
            [a addObject:@"foo"];
        }
        NSLog(@"%lu rounds of 10,000,000 completed", i+1);
    }

    [a release];

    [pool drain];
    return 0;
}

..そのまま実行すると、最終的に EXC_BAD_ACCESS で終了します。(私はこれを 32 ビット アプリとしてコンパイルして実行したので、2**32 個のオブジェクトをヒットすると確実にスペースが不足する可能性がありました。

つまり、例外をスローするのはいいことですが、実際に何もする必要はないと思います。

于 2010-03-07T18:16:19.500 に答える
0

アサーションとカスタム アサーション ハンドラーを使用することが、利用可能な最良のオプションである場合があります。

アサーションを使用すると、コード内に多くのチェックポイントを簡単に作成でき、そこで物事が正常に機能することを確認できます。そうでない場合、デフォルトでは、アサーション マクロはエラー (開発者定義の文字列) をログに記録し、例外をスローします。また、カスタム アサーション ハンドラーを使用してデフォルトの動作をオーバーライドし、別の方法でエラー状態を処理することもできます (例外のスローを回避することもできます)。

このアプローチにより、柔軟性が大幅に向上し、エラー処理戦略 (例外をスローするか、エラーを内部で処理するか) をいつでも簡単に変更できます。

ドキュメントは非常に簡潔です: Assertions and Logging

于 2010-03-09T18:09:40.237 に答える