質問

最近のプロジェクトに取り組んでいるときに、顧客の QA 担当者が訪問し、これまであまり考えたこともなかった質問をされました。

使用しているコンパイラーが C コードの機能と正確に一致するマシンコードを生成していること、およびコンパイラーが完全に決定的であることは、どのようにしてわかりますか?

私はコンパイラを常に当然のことだと思っていたので、この質問に対しては全く答えられませんでした。コードを取り込み、マシンコードを吐き出します。コンパイラが実際に私が要求していない機能を追加していないかどうかをテストするにはどうすればよいでしょうか?それとも、私が期待するものとは少し異なる方法でコードを実装するさらに危険な方法でしょうか?

おそらくこれがすべての人にとって実際の問題ではないことは承知していますが、実際、その答えは次のようなものかもしれません...「あなたはバレルを超えています、そしてそれに対処してください。」ただし、組み込み環境で作業する場合は、コンパイラを暗黙的に信頼します。自分の行動が正しいことを自分自身と QA に証明するにはどうすればよいですか?

役に立ちましたか?

解決

安全性を重視するため、組み込みアプリケーションの認証機関は、コンパイラの「使用実績」要件を満たす必要があります。通常、詳細な文書によって満たされ、証明される必要がある特定の要件 (「稼働時間」のようなもの) があります。ただし、特に新しいターゲット/コンパイラを使用する最初のプロジェクトでは非常に難しいため、ほとんどの人はこれらの要件を満たすことができないか、満たしたくないのです。

もう 1 つのアプローチは、基本的にコンパイラーの出力をまったく信頼しないことです。コンパイラ、さらには言語依存 (C-90 標準の付録 G) の欠陥は、その後の機能テストに加えて、一連の厳密な静的解析、単体テスト、およびカバレッジ テストによってカバーする必要があります。

のような標準 ミスラ-C コンパイラへの入力を C 言語の「安全な」サブセットに制限するのに役立ちます。別のアプローチは、コンパイラへの入力を言語のサブセットに制限し、サブセット全体の出力がどのようなものであるかをテストすることです。アプリケーションがサブセットのコンポーネントのみで構築されている場合、コンパイラーの出力がどのようになるかはわかっていると想定されます。通常は「コンパイラの資格」によって決まります。

これらすべての目標は、QA 代表者の質問に「コンパイラの決定論に依存するだけではなく、これがそれを証明する方法です...」と答えられるようになることです。

他のヒント

この引数はどのレベルでも適用できます。サードパーティのライブラリを信頼しますか?OSを信頼しますか?プロセッサーを信頼しますか?

もちろん、これが正当な懸念である理由の良い例は、Ken Thompson が元の「ログイン」プログラムにバックドアをどのように入れたかです...C コンパイラを変更して、ログインを再コンパイルした場合でもバックドアを取得できるようにしました。これを参照してください 投稿する 詳細については。

暗号化アルゴリズムについても同様の疑問が提起されています。DES に NSA が覗き見できるバックドアが存在しないことは、どうやってわかるのでしょうか?

最後には、構築しているインフラストラクチャを心配しなくてもよいほど信頼できるかどうかを判断する必要があります。そうでない場合は、独自のシリコン チップの開発を開始する必要があります。

テストすればわかります。テストするときは、コードとコンパイラの両方をテストすることになります。

あなたまたはコンパイラ作成者がエラーを起こす確率は、問題のプログラムをアセンブリ言語で書いた場合にエラーを起こす確率よりもはるかに小さいことがわかります。

利用可能なコンパイラ検証スーツがあります。
私が覚えているのは、 「多年草」.

私が組み込み SOC プロセッサ用の C コンパイラに取り組んでいたとき、これと他の 2 つの検証スーツ (名前は忘れました) に対してコンパイラを検証する必要がありました。コンパイラがこれらのテストスーツに一定レベル準拠していることを検証することは契約の一部でした。

すべては信頼に帰着します。あなたの顧客はコンパイラを信頼していますか?それを使用するか、少なくともあなたの出力コードと彼らの出力コードを比較してください。

何も信頼できない場合、その言語のリファレンス実装はありますか?彼らにそれを信頼してもらえるよう説得してもらえますか?次に、自分のものをリファレンスと比較するか、リファレンスを使用します。

これはすべて、ベンダー/プロバイダーから取得した実際のコードを実際に検証し、コンパイラーが改ざんされていないことを確認することを前提としています。これが最初のステップとなるはずです。

いずれにしても、リファレンスを持たずにコンパイラを最初からどのように検証するかという疑問が残ります。これは確かに膨大な作業のように見えますし、言語の定義が必要ですが、常に利用できるわけではなく、定義がコンパイラである場合もあります。

使用しているコンパイラーが C コードの機能と正確に一致するマシンコードを生成していること、およびコンパイラーが完全に決定的であることは、どのようにしてわかりますか?

そうしないのが、結果として得られたバイナリをテストする理由であり、テストに使用したものと同じバイナリを必ず出荷する理由です。そして、ソフトウェアに「軽微な」変更を加えるときに、古い機能が壊れていないことを確認するために回帰テストを行うのはなぜでしょうか。

私が認定した唯一のソフトウェアはアビオニクスです。FAA 認定は、ソフトウェアが正しく動作することを証明できるほど厳格ではありませんが、同時に一定のハードルを飛び越えることを強いられます。コツは、無関係なフープジャンプをできるだけ少なくして、品質をできる限り向上させるように「プロセス」を構造化することです。したがって、価値がなく、実際にバグが見つからないとわかっているものは、おそらくイタチで取り除くことができます。そして、あなたがすべきだと知っていることは何でも、 意思 FAA から明示的に要求されていないバグを見つける場合、最善の策は、FAA や QA 担当者に要求された内容を提供しているように聞こえるまで言葉をねじ曲げることです。

これは実際のところ、私が思っているほど不誠実ではありません。一般的に、FAA はあなたが良心的で、誠実であることに自信があるかどうかを重視しています。 試しています 具体的に何をするかということよりも、良い仕事をすること。

防衛ソフトウェアエンジニア向けの雑誌「Crosstalk」には、知的な弾薬が見つかるかもしれません。この質問は、彼らが起きている時間の多くを費やす類の質問です。 http://www.stsc.hill.af.mil/crosstalk/2006/08/index.html (古いプロジェクトの古いメモを見つけることができたら、ここに戻ってきます...)

たとえ強く推奨されているコンパイラーであっても、そのコンパイラーを完全に信頼することはできません。彼らはバグのあるアップデートをリリースし、あなたのコードは同じようにコンパイルされる可能性があります。この問題は、バグのあるコンパイラで古いコードを更新し、テストを行って商品を出荷した後、3 か月後に顧客から問題について電話がかかってきた場合にさらに悪化します。

すべてはテストに戻りますが、私が学んだことが 1 つあるとすれば、些細な変更があった場合には徹底的にテストすることです。問題を見つけるのが不可能と思われる場合は、コンパイルされたアセンブラを見て、すべきことを実行しているかどうかを確認してください。

何度かコンパイラにバグを見つけました。あるとき、16 ビット変数がキャリーなしで、16 ビット変数がヘッダー ファイルで定義された extern 構造体の一部である場合にのみインクリメントされるというバグがありました。

...コンパイラを暗黙的に信頼している

コンパイラのバグに初めて遭遇したら、それをやめるでしょう。;-)

しかし、最終的にはこれがテストの目的です。そもそもバグがどのようにして製品に侵入したかは、テスト体制にとっては問題ではありません。重要なのは、それが広範なテスト体制に合格しなかったことだけです。

良い..特に埋め込みコードを扱う場合には、コンパイラの出力を単純に信頼するとは言えません。まったく同じコードを異なるコンパイラでコンパイルすると、生成されたコード間の不一致を見つけるのは難しくありません。これは、C 標準自体が緩すぎるためです。多くの詳細は、標準を破ることなく、コンパイラごとに異なる方法で実装できます。このようなことにどう対処すればよいでしょうか?可能な限り、コンパイラに依存する構造を避けます。C のより安全なサブセットを選択することでこれに対処できるかもしれません。 ミスラ-C ユーザー cschol が前述したように。コンパイラーによって生成されたコードを検査する必要はほとんどありませんが、それが時々起こることもあります。しかし、最終的には、コードが意図したとおりに動作するかどうかを確認するために、テストに依存することになります。

もっと良い選択肢はあるでしょうか?あると主張する人もいます。もう 1 つのオプションは、コードを次のように記述することです。 スパーク/エイダ. 。私は SPARK でコードを書いたことはありませんが、「ベアメタル」のものを処理する C で書かれたルーチンに SPARK をリンクする必要があると理解しています。SPARK/Ada の利点は、どのコンパイラーによって生成されたコードも常に同じであることが完全に保証されていることです。曖昧さは一切ありません。さらに、この言語を使用すると、コードがどのように動作するかを説明する注釈をコードに付けることができます。SPARK ツールセットは、これらのアノテーションを使用して、記述されたコードが実際にアノテーションで記述されたことを実行することを正式に証明します。したがって、重要なシステムにとっては、SPARK/Ada がかなり良い選択肢であると言われています。私自身試したことはありませんが。

コンパイラが期待どおりの動作をするかどうかはわかりません。理由はもちろん、 コンパイラはソフトウェアの一部です, 、そのためバグの影響を受けやすいです。

コンパイラ作成者には高品質の仕様に基づいて作業できるという利点がありますが、残りの私たちは作業を進めながら何を作成しているのかを理解する必要があります。ただし、コンパイラの仕様 また バグがあり、微妙な相互作用を伴う複雑な部分があります。したがって、コンパイラーが何をすべきかを理解するのは決して簡単ではありません。

それでも、言語仕様が何を意味すると思うかを決めたら、あらゆるニュアンスに対応する優れた高速な自動テストを作成できます。これは、コンパイラーの作成が他の種類のソフトウェアの作成に比べて大きな利点がある点です。テスト中。すべてのバグは自動化されたテスト ケースになり、テスト スイートは非常に徹底的なテストを行うことができます。コンパイラ ベンダーは、コンパイラの正確性を検証するために、あなたよりもはるかに多くの予算を投資しています (あなたはすでに本業を持っていますよね?)。

これはあなたにとって何を意味しますか?これは、コンパイラにバグが存在する可能性を受け入れる必要があることを意味しますが、自分ではバグを見つけることはできない可能性があります。

私なら、すぐに廃業する可能性が低く、コンパイラに高品質の歴史があり、製品にサービス (パッチ) を提供する能力を実証しているコンパイラ ベンダーを選びます。コンパイラは時間の経過とともにより正確になるようですので、10 年か 20 年ほど前のコンパイラを選択することをお勧めします。

コードを正しくすることに注意を集中してください。 もし 明確でシンプルな, 、そして、あなたが する コンパイラのバグに遭遇したとしても、問題がどこにあるのかを判断するために真剣に考える必要はありません。 適切な単体テストを作成する, これにより、コードが期待どおりに動作することが保証されます。

単体テストを試してください。

それでも十分でない場合は、別のコンパイラを使用して単体テストの結果を比較してください。strace 出力を比較し、VM でテストを実行し、ディスクとネットワーク I/O のログを保存して、それらを比較します。

あるいは、独自のコンパイラを作成して、それにかかる費用を伝えることを提案してください。

簡単に証明できるのは、プロバイダ X の改ざんされていないコンパイラを使用しているということだけです。彼らがプロバイダー X を信頼しない場合、それは彼らの問題です (X が十分に信頼できる場合)。どのコンパイラ プロバイダも信頼しないのであれば、まったく不合理です。

彼らの質問に答えると次のようになります。これらの手段を通じて、X の改ざんされていないコンパイラを使用していることを確認します。X は評判が良く、アプリケーションが期待どおりに動作することを示す優れたテストのセットも用意されています。

他のすべてのことが虫の缶を開け始めています。ロブが言うように、どこかで立ち止まらなければなりません。

積極的なレベルの最適化を要求すると、動作が変化する場合があります。

最適化と浮動小数点数はどうでしょうか?忘れて!

ほとんどのソフトウェア開発 (デスクトップ アプリケーションを考えてください) の答えは、おそらく「分からない、気にしない」ということでしょう。

安全性が重要なシステム (原子力発電所や商用アビオニクスを考えてください) では、 する 介護機関や規制当局はそれを証明することを要求します。私の経験では、次の 2 つの方法のいずれかでこれを行うことができます。

  1. 認定されたコンパイラを使用します。「認定された」とは、規制当局が定めた基準に従って検証されたことを意味します。
  2. オブジェクトコード分析を実行します。基本的には、リファレンス コードをコンパイルし、その出力を手動で分析して、ソース コードを追跡できない命令がコンパイラーによって挿入されていないことを実証します。

ディクストラが書いたものを入手します。

Compcert C コンパイラなど、正式に検証されたコンパイラを選択します。

  1. コンパイラの最適化レベルを変更すると、出力が変わります。
  2. 関数にわずかな変更を加えると、コンパイラがインライン化されたり、関数がインライン化されなくなる場合があります。
  3. コンパイラ (gcc バージョンなど) を変更すると、出力が変更される場合があります。
  4. 特定のライブラリ関数は組み込みである (つまり、最適化されたアセンブリを出力する) 場合がありますが、その他のほとんどは組み込みではありません。

幸いなことに、ほとんどの場合、それは実際にはそれほど重要ではありません。それが本当に重要な場合 (ISR など)、アセンブリを検討することをお勧めします。

目に見える結果をもたらさない予期せぬマシン コードが心配な場合、唯一の方法はおそらくコンパイラ ベンダーに問い合わせて、顧客を満足させる何らかの認証を取得することです。

それ以外の場合は、コード内のバグ、つまりテストについて知っているのと同じように知ることになります。

最新のコンパイラーからのマシンコードは大きく異なっており、ちっぽけな人間にはまったく理解できない場合があります。

この問題を次のように還元することができると思います。 停止問題 どうにか。

最も明白な問題は、ある種のプログラムを使用してコンパイラとその決定論を分析する場合、それをどうやって知ることができるかということです。 あなたの プログラムは正しくコンパイルされ、正しい結果が生成されますか?

ただし、別の「安全な」コンパイラを使用しているかどうかはわかりません。私が確信しているのは、コンパイラーを最初から書くほうがおそらく簡単な仕事であるということです。

認定または認定されたコンパイラーであっても、望ましくない結果が生じる可能性があります。コードをシンプルにして、テスト、テスト、テストを繰り返します。あるいは、人的ミスを許さずに、機械コードを手動で実行することもできます。さらに、オペレーティング システムまたは実行している環境 (できればオペレーティング システムは使用せず、プログラムのみ)。

この問題は、ソフトウェアとコンパイラが登場して以来、ミッション クリティカルな環境では解決されてきました。他の回答者もご存知のとおりです。各業界には、認定コンパイラーからプログラミング スタイル (常にこの方法でプログラムする必要があり、あれやこれやを決して使用しないでください)、多くのテスト、ピアレビューに至るまで、独自のルールがあります。あらゆる実行パスの検証など

これらの業界に属していなくても、得られるものは得られます。COTS ハードウェア上の COTS オペレーティング システム上の商用プログラム。それは失敗します、それは保証です。

心配な場合は 悪意のある コンパイラにバグがある場合、1 つの推奨事項 (IIRC、一部のプロジェクトに対する NSA 要件) は、コンパイラのバイナリがコードの作成よりも前のものであることです。少なくともそうすれば、誰も持っていないことがわかります 追加した 対象となるバグ あなたの プログラム。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top