6

いくつかのバイナリデータ(画像など)を受け入れて何かを実行するC++のSDKがあるとします。このSDKを「クラッシュプルーフ」にすることはできませんか?クラッシュとは、主に、ユーザーから渡された無効な入力(異常に短いジャンクデータなど)が原因で、メモリアクセス違反時にOSが強制的に終了することを意味します。

私はC++の経験がありませんが、グーグルで検索したところ、解決策のように聞こえるいくつかの手段が見つかりました(配列の代わりにベクトルを使用する、自動境界チェックが実行されるようにコンパイラーを構成するなど)。

私がこれを開発者に提示したとき、彼はそれがまだ不可能であると言いました。私が彼を信じていないというわけではありませんが、もしそうなら、Javaのような言語はこれをどのように処理しますか?JVMは境界チェックのたびに実行されると思いました。もしそうなら、なぜC ++で同じことを手動で行うことができないのですか?

UPDATE
「クラッシュプルーフ」とは、アプリケーションが終了しないという意味ではありません。何が起こったのかを知らずに突然終了してはいけないということです(コアダンプなどはありますが、「引数xが無効でした」などのメッセージを表示することはできませんか?)

4

8 に答える 8

6

C ++で配列の境界を確認できstd::vector::atます。これは、自動的に行われます。

これはアプリのクラッシュを防ぐものではありません。意図的に足を撃つことは許可されていますが、C++ではトリガーを引く必要はありません。

于 2010-12-23T06:02:18.770 に答える
4

いいえ。コードにバグがないとしても。1つは、自動的に送信される多くのクラッシュレポートを確認したことです。ハードウェアの品質は、ほとんどの開発者が期待するものをはるかに下回っています。ビットフリップはコモディティマシンでは非常に一般的であり、ランダムなAVを引き起こします。また、アクセス違反を処理する準備ができている場合でも、OSがプロセスを終了する以外に選択肢がないという特定の例外があります。たとえば、スタックガードページのコミットの失敗などです。

于 2010-12-23T06:02:58.777 に答える
4

クラッシュとは、主に、ユーザーから渡された無効な入力(異常に短いジャンクデータなど)が原因で、メモリアクセス違反時にOSが強制的に終了することを意味します。

これは通常起こることです。無効なメモリにアクセスすると、通常、OSはプログラムを中止します。

ただし、無効なメモリとは何ですか...ヒープとスタック内のすべてのメモリを自由にガベージで埋めることができます。これは、OSの観点からは有効ですが、ガベージを作成したときの観点からは有効ではありません。

基本的に-入力データを注意深くチェックし、これを中継する必要があります。これを行うOSはありません。

入力データを注意深くチェックすれば、データを問題なく管理できる可能性があります。

于 2010-12-23T06:04:22.183 に答える
3

私は主に、ユーザーから渡された無効な入力による、メモリアクセス違反時のOSによる強制終了を意味します

「ユーザー」が誰であるかわからない。

無効なエンドユーザー入力が原因でクラッシュしないプログラムを作成できます。一部のシステムでは、メモリの使用量が多すぎるため(または、他のプログラムがメモリの使用量が多すぎるため)、強制的に終了する場合があります。そして、Remusが言うように、ハードウェア障害から完全に保護できる言語はありません。ただし、これらは、ユーザーが提供するデータのバイト数以外の要因によって異なります。

C ++で簡単に実行できないことは、無効な入力が原因でプログラムがクラッシュしたり、さらに悪い方法で失敗したりして、重大なセキュリティ上の欠陥が発生しないことを証明することです。そのため、[*]コードはどの入力に対しても安全だと思うことがありますが、そうではないことがわかります。あなたの開発者はこれを意味するかもしれません。

コードが、たとえば画像データへのポインターを受け取る関数である場合、呼び出し元が無効なポインター値を渡すのを止めるものは何もありません。

char *image_data = malloc(1);
free(image_data);
image_processing_function(image_data);

したがって、関数自体を「クラッシュプルーフ」にすることはできません。プログラムの残りの部分がクラッシュさせるために何もしない必要があります。あなたの開発者もこれを意味するかもしれないので、おそらくあなたは彼に明確にするように頼むべきです。

Javaは、無効な参照を作成できないようにすることでこの特定の問題に対処します。Javaで手動でメモリを解放することはできないため、特に、そうした後は参照を保持できません。他の多くの特定の問題を他の方法で処理するため、C ++では「未定義動作」であり、クラッシュを引き起こす可能性がある状況では、Javaでは別のことが行われます(おそらく例外がスローされます)。

[*]それに直面しましょう:実際には、大規模なソフトウェアプロジェクトでは「しばしば」。

于 2010-12-23T11:04:10.230 に答える
1

これは、C++コードがマネージドコードではない場合だと思います。

Java、C#コードは管理されます。つまり、境界チェックを実行し、クラッシュ状態を検出できるインタープリターによって効果的に実行されます。

C ++の場合、バウンドやその他のチェックを自分で実行する必要があります。ただし、例外処理を使用すると、制御できないイベント中のクラッシュを防ぐことができます。

要するに、C ++コード自体はクラッシュプルーフではありませんが、優れた設計と開発により、クラッシュプルーフになる可能性があります。

于 2010-12-23T06:07:05.353 に答える
1

一般に、C++ API をクラッシュ防止にすることはできませんが、より堅牢にするために使用できる手法があります。あなたの特定の例について、私の頭の上から(そして決して網羅的ではありません):

  • 可能な場合は入力データのサニティチェック
  • データ処理コードでのバッファ制限チェック
  • エッジおよびコーナーケースのテスト
  • ファズテスト
  • 回帰を回避するために問題の入力を単体テストに入れる
于 2010-12-23T07:11:13.780 に答える
0

「クラッシュプルーフ」とは、クラッシュが発生した後にクラッシュを調査するための十分な情報があることを確認することだけを意味する場合、解決策は簡単です。クラッシュ中にデバッグ情報が失われるほとんどの場合、スレッドの1つで実行されているコードによる不正なメモリ操作による破損やスタックデータの損失が原因です。信頼できないライブラリまたはSDKを呼び出す場所がほとんどない場合は、部分的または完全なメモリダンプに含まれるグローバル変数が指すメモリ位置でそのライブラリを呼び出す直前に、スタックトレースを保存するだけです。アプリケーションがクラッシュしたときにシステムによって生成されます。Windowsでは、CrtDbg APIによって提供されるこのような機能。Linuxでは、バックトレースAPIを使用できます。show_stackframe()でドキュメントを検索するだけです。スタック情報を失った場合は、ダンプファイルをロードした後、メモリ内のその場所をスタックの最上位として使用するようにデバッガーに指示できます。結局のところ、それはそれほど単純ではありませんが、何が起こったのかわからないままメモリダンプに悩まされている場合は、役立つ可能性があります。組み込みアプリケーションでよく使用されるもう1つのトリックは、詳細なログ記録のための循環メモリバッファです。バッファへのロギングは保存されないため非常に安価ですが、クラッシュ後のメモリダンプ内のバッファの内容を確認することで、クラッシュの数ミリ秒前に何が起こるかを知ることができます。

于 2011-01-09T07:19:15.243 に答える
-1

実際、境界チェックを使用すると、アプリケーションがクラッシュする可能性が高くなります。

これは、プログラムが機能している場合、正しく機能するのではなく、/正しく/機能する可能性がはるかに高いことを意味するため、優れた設計です。

とはいえ、停止問題が解決されるまで、厳密に言えば、特定のアプリケーションを「クラッシュプルーフ」にすることはできません。幸運を!

于 2010-12-23T06:04:37.037 に答える