web-dev-qa-db-ja.com

segfaultは常にプログラマーの間違いですか?

Segfault(配列インデックスが範囲外)は常にプログラマーの間違いですか、それともユーザーの誤用ですか?

6
Niklas

仕様の一部が「そのような状況では、未定義の動作を呼び出す」(C/C++)または「IndexOutOfBoundsExceptionをトリガーする」でない限り、それは常にプログラマーの責任です。

プログラムのタスクは、すべての入力に適切に対応することです。これには、不完全な入力、不完全な入力、または積極的に破壊的な入力も含まれます。一般に、ユーザーが使用できない入力を提供した場合、プログラムは、ランタイムシステムによる実装定義の反応ではなく、エラーメッセージや繰り返しプロンプトなどの明確な応答を提供する必要があります。このような振る舞いは、通常ユーザーには役に立たず、セキュリティの脆弱性を引き起こす可能性があります。

24
Kilian Foth

いいえ、ハードウェアが宇宙線にぶつかることがあります。

エラー訂正機能のないハードウェアでは、半導体メモリに高エネルギーの放射線が当たったときに1ビットをフリップするのが一般的です。これがループカウンタまたはアドレスレジスタのビットである場合、間違ったアドレスにアクセスする原因になります。航空宇宙アプリケーション用に作成されたソフトウェアと初期のGPGPUソフトウェアは、通常、冗長システムと投票を使用して、ハードウェアの強化にコストがかかりすぎていたこの問題を回避しました。

このNASAの論文 は、この現象を軽減するためのソフトウェア技術に関する詳細情報を提供しています。ウィキペディアで 放射線硬化エレクトロニクス をいつでも確認できます。 このホワイトペーパー GPUでのシミュレーションにおけるエラー修正の影響について説明します-初期のGPUでのエラーの主な原因が放射であるか他のエラーであるかは、手元で思い出せません ソフトエラー =。

17
Pete Kirkham

他の人が正しく述べているように、それはプログラマの責任ですが、JavaおよびCを要求したので、違いを説明したいと思います。

Cで

プログラムは、配列を使用するすべての状況で、このような状況が発生しないようにする必要があります。インデックス変数が配列の境界を超えないようにしてください。さもなければ、これは未定義の、予測できない振る舞いを引き起こし、そしておそらくセキュリティの問題になります。

この種の予測できない動作により、これを起こさないことがプログラマの責任であることは明らかです。

Javaで

あなたはこれを防ぐことができますが、そうしなくても、プログラムは定義された方法で動作します:特定の例外をスローします。その後、プログラムは、コールスタックのどのレベルでも、この例外をキャッチする機会があります(ほとんどの実際のケースでは、それが可能です)。

そうでない場合、Javaランタイム環境は、ユーザーの観点からはおそらくあまり役​​立たない可能性が高い技術エラーメッセージとともに、プログラムを正常に終了します。これが許容できる動作の場合ですが、ほとんどのプログラムでは、ユーザーとして、「範囲外の配列」が予期しない入力パラメーターによって引き起こされた場合、プログラムから次のように通知されますwhat inputパラメータはおそらく間違っていましたが、それは自動的には行われません。これを実装する必要があります。

したがって、プログラムが非常にユーザーフレンドリーでない方法で反応しないようにするには、より有用なエラーメッセージを生成することもプログラマの責任です。

6
Doc Brown

はい、それは常にプログラマーの責任です。彼は自分の長さの計算を台無しにしたか、ユーザー入力を適切にサニタイズしませんでした。

ほとんどいつも。

プログラマーのミスではない場合:

  1. 故意である場合(例:segfaultの取得方法の例)
  2. それがハードウェアの故障であるとき
  3. 誰かがプログラムまたはその環境を改ざん/変更したとき(電源の変更、コンピュータへの照射、メモリ内のデータの変更、実行可能ファイルの変更(ただし、元のプログラムですか?プログラマは誰ですか))

  4. 契約がプログラマーが予期しない入力を処理するための時間を請求できないと具体的に何が起こるかIS未定義の動作です。

0
user470365

ユーザーの誤用でしょうか?

はい。

ユーザーがアプリケーションを誤用する方法は無数にあります。たとえば、不適切なライブラリを提供したり、互換性のないプラグインをロードしたりするなど、適切なアプリケーションが防御できないものもあります。

0
Peter Green

Segfaultはありますか?alwaysプログラマの間違い...?

番号。

Segfaultは... ときどきプログラマの間違い...?

はい。
誰もが間違いをする可能性があります。

Segfaultです...時々ser's間違い...?

直接ではありません。

ユーザーは有効であると信じていることを行いますが、アプリケーションはこれを誤って解釈し、アプリケーションコードを破損させるデータを生成します。

私のマントラ:

Bad Code breaks.  Period.  
Good Code gets broken by Bad Data. 

コードが根本的に間違っている場合、alwaysは失敗します。その場合、ほとんどのスタックトレースで提供されているように、エラーが発生した場所を知るだけで、問題を見つけて修正することができます。

コードは基本的に正しいが開発者がたとえばEdgeケースを逃した場合、コードwillは依然として壊れますが、-wherenotであることがわかりますそれを修正するのに十分です。 原因破損という入力データを知る必要もあります。これは、StackTracesがめったに提供しないことです。

0
Phill W.

一般的に言えば、ユーザーがプロンプト(またはダイアログボックス)に不正なデータを入力するだけでプログラムをクラッシュさせることができる場合、プログラマーはdefinitelyに問題があります。人々は(時には故意に)間違いを犯し、自分のコードを実装するときにそれを考慮に入れないプログラマーは過失です。これは特に Cでtrueです。これは、配列の終わりなどのインデックスを作成したときに、IndexOutOfBounds例外がスローされないためです。

いくつかの間違いは想像力の失敗です(いいえway誰もが単一の入力に対して128文字を超える文字を入力します)、いくつかは単にエッジのケース(数値のオーバーフロー、ゼロによる除算など)を考慮していません。いくつかは、分離してうまく機能するが、どういうわけかお互いのデータを踏む異なるコードの断片間の相互作用の結果です。コードを開発するとき(特に急いでいるとき)は、トンネルビジョンに悩まされることが多いため、不適切な入力でコードを適切に実行しません。

残念ながら、Cでの入力チェックとサニタイズはお尻の痛みです。防弾scanfは、多くの場合、無駄な作業です。そのため、多くの場合、fgetsを使用してすべてをテキストとして読み取り、必要に応じて解析および変換します。これにより、コードのサイズが膨らみます(- この答え は、それがどれほどばかげているかを示しています)。

さて、ユーザーがis n'tプロンプトで入力を入力するだけの場合(たとえば、それをgdbの下で実行し、フードの下で何かをいじる)、それはプログラマーが必ずしも保護できるものではありませんに対して。

0
John Bode

これは明らかにアプリケーションに依存します。

一度だけ使用するアプリケーションをまとめてすばやくハッキングしたい場合、完全なポインターチェックを追加するのは賢明ではありません。この場合、segfaultは、無効なデータをアプリケーションに入力したことを意味する場合があります。もちろん、Pythonなどの高水準言語を使用することもできますが、パフォーマンスが重要な場合、Pythonは遅すぎる可能性があります。

ただし、製品レベルのソフトウェアでは、segfaultは受け入れられないので、プログラマーの責任です。想像してみてください無効なネットワークパケットが原因のセグメンテーションフォルト。これにより、アプリケーションにリモートクラッシュの脆弱性が生じる可能性があります。

0
juhist

Cの場合、「いいえ」と言います。ユーザー/クライアントエラーの可能性があります。たとえば、ポインタを受け入れるすべての関数が、ポインタがnullであるかどうかをチェックすることにより、コードの保守性と計算効率を必ずしも浪費する必要があるわけではありません。またはそれにぶら下がっているポインタ。そうすることで、他の場所にあるバグを覆い隠し始める可能性さえあります。

関数を実装する人々の責任であると考えた場合、C標準ライブラリの大部分が壊れてバグがあり、エピックな書き換えが必要になります。無効な入力を渡すだけでC標準ライブラリの多くの関数をsegfaultできるからです。 (例:qsortバッファの終わりを超えた)。または、qsortのような関数に無効なポインターを渡す人はそれを誤って使用していると言うことができますが、これははるかに実用的な見方です。

とにかく、関数内で後者のケース(ダングリングポインター)を効果的にチェックすることもできません。 C関数は、その関数に対して無効な入力を渡すと、それらを使用または呼び出す人によって無限に誤用される可能性があるため、Cインターフェースの誤用が、セグメンテーション違反につながる「ユーザーエラー」の結果である場合が多くあります。その他のクラッシュ。

プログラマーのエラーやインターフェースを使用するユーザーのミスを検出する関数を作成する場合、Cは一般的にジョブにとって不適切な言語です。実際、Cの魅力の大部分は、Cが誤用されるとセグメンテーション違反が発生し、見事にクラッシュする傾向があることです。私はテストのレーダーの下で簡単に飛ぶことができるバグを検出するのが難しいよりもそれを好みます。

今、私は「ユーザー」を想定しています。あなたは誰かが関数を呼び出すことを意味します。アプリケーションの「エンドユーザー」ではなく、関数またはライブラリの「ユーザー」。エンドユーザーについて話している場合、たとえば、プラグイン開発者がAPIのCプラグインを作成していない限り、誤用の結果としてプログラムがクラッシュすることはありません。プロダクションソフトウェアは、たとえば、入力フィールドが大きすぎてソフトウェアをセグフォルト化する可能性のあるGUIでユーザーに入力フィールドを表示するべきではありません。ソフトウェアはそのような誤用を許すべきではありません。

0
user204677