なぜC言語プログラムは磐石のように堅固なのか.


2008年11月11日(Single Day~~~)
C言語は、今日では特殊なプログラミング言語です.ごく少数の人だけが本当にCでプログラミングすることができ、私たちの多くの人はCに対して自分の見方を持っています.バッファオーバーフロー、スタックオーバーフロー、整数データオーバーフロー、Cにはよく知られている欠陥がたくさんありますが、これらの欠陥は人々に勝手に伝播され、Cに慣れていない人々さえいます.私自身はすでにCに接触していない10念があって、このようにあるいはそのような原因のためです.最初の額は、コンパイラが高価(無料のUNIXがリリースされる前に)で遅く、その時の環境は最悪でした.そして、Cに関するすべてのホラーストーリーは、私のような小さな普通のプログラマーが信頼できるCプログラムを書くことができると思います.
私が直接別の場所からコピーして貼り付けた多くの小さなCモジュールを置いて、私が自分で書いた最初のCプログラムはConverge VMです.その中に2つのことが私を驚かせた:-o.第一に、Cプログラムを書くのはそんなに難しくなかった.私が若い頃にアセンブリコードを書く時間を無駄にしたことが心理的に大きな支持を与えてくれたことを後で知った.結局Cは高級なアセンブリ言語だった.ポインタ(低級言語の中で最も微妙な概念と言えるが、実世界には対応する比喩がないため)のような概念を一人で理解すると.2つ目は、Converge VMが私が期待していたようにバグだらけではないことです.
実際、どのプログラミング言語にも存在する可能性のある論理エラーを無視し、これまでConverge VMで実際の問題を引き起こしたのはCのみに対するエラーが2つしかありません(アイデア、私はまだ潜伏しているバグがたくさんあるに違いありませんが、私の状況はまだあまりぶつかっていません).最初のエラーは、listが\0(Cの古典的なエラー)ではなく、この問題をデバッグするのに長い時間がかかったことです.もう一つの間違いは不思議で、何ヶ月もかかりました.Convergeゴミ回収器は、ポインタに従って勝手に割り当てられたメモリ領域を慎重に回収することができます.すべての現在の構造では、ポインタは字と字の位置合わせの境界を指します.しかしながら、割り当てられたメモリブロックは、長さにおいて字と字が整列していないことが多い.(In all modern architectures,pointers have to live on word-aligned boundaries.However,malloc'd chunks of memory are often not word-aligned in length.)したがって、ゴミ回収器はメモリブロックの位置が4の場所で4 bytesの読み取りを試みることがあります.つまり、そのメモリブロックが5 bytes長になるようにします.言い換えれば、ゴミ回収器は、理論的に権限のない3 bytesランダムデータを1つのデータの1 bytesとメモリに読み込もうと試みる.珍しく不思議なことに、これによる間違いはほとんど説明できません.しかし、誇張しないで、どれだけのプログラミング言語の中で一人でゴミ回収器を再帰的に加えることができますか?
私とConverge VMの経験はあまり私の以前の偏見に合わない.私はCプログラムがランダムにsegfaultが現れ、データを失うことを徐々に認めています.そして、Vikings(ウィキョン海賊)がLindisfarneに行くようによくあります.対照的に、高度な言語で作成されたプログラムは、通常の論理と予想可能なパターンに従ってエラーを報告します.だんだん、これらの問題は私が日常的に使っている私が信頼できるCで書いたプログラムの中で、私はすべて出会った.前回これらのプログラムに大きな問題が発生した時を覚えていません.これらは崩れず、二次的な間違いを優雅に処理します.たとえ、私はこれらのソフトウェア(OpenBSDを使って9年になるので、これらの品質より良いソフトウェアはありません)に対して極度に文句を言っても、なぜそれがこんなに信頼できるのかは明らかです.それは多くの人に使われていて、これらの人は私たちにバグを見つけるのを助けています.ソフトウェアは長い間開発されていたので、以前のバージョンにはバグがありました.そして、率直に言って、かなり有能なプログラマーだけがCに傾いています.しかし、なぜCで書かれたプログラムが磐石のように堅固なのかという根本的な問題が残っている.
論文を書く暗い時期を過ぎた後、私は最近Cプログラミングを少ししました.長い間手書きのCプログラムを持っていない人には、適切にメールを送りたいと思ってもスペクトルがありません.ここ数年、私はsshを通じて遠隔機器でsendmailでメールを送信しています.これにより、ブラックリストなどの多くの問題が解決され、多くのネットワークでも問題(特にワイヤレスネットワーク)があり、ネットワーク接続が多すぎると捨てられます.メールが送信されているかどうかをチェックするのは煩わしい過程です.だから、そのデザインをよくチェックした後、sshを通じてメールを確実に送信するために簡単なツールセットを書くつもりです.最終的なプログラム-extsmail-は私が以前期待していたよりも多くの機能を持っていますが、最も基礎的な考え方は、外部のコマンド、例えばsshを通じて簡単にメールを再試行して、成功するまで送信することです.また、このツールセットにできるだけリソースを消費しないで実用的にし、移植したいと思っています.これは必然的にCでextsmailを書くべきだと決定します.そして私はできるだけこのプログラムを書いてみることにしました.実験だと思ってください.従来のUNIX方式では,信頼できるUNIX配布版が提供する機能のみに依存し,フォールトトレランス能力が強い.やっているうちに、Cでプログラムを書く初心者の観察資料を2つ作りました.
最初の観察はあまり明らかではない.Cで書かれたプログラムには数え切れないほどの間違いがあるので、いつもより細心の注意を払っています.特に、メモリブロックの操作によって、非常に危険なバッファオーバーフロータイプエラーが発生します.しかし、高級言語では、「ええと、インデックス配列を作るときはこの値を1つ減らすべきではないでしょうか.まず走ってみましょう」と怠け者になるかもしれません.Cでは「OK、座って理由を考えて」と思います.皮肉なことに、プログラムを走るのと問題を発見するのにかかる時間と座って考える時間は違い、座って考える以外に頭がかかります.
2つ目の観察は、私がこれまで出会ったことがなく、Cで異常な処理はありませんでした.もし、例えばextsmailであれば、フォールトトレランス能力を高めるには、可能なすべてのエラーを自分で処理しなければなりません.一方、これは非常に苦痛であり、extsmailの多くの割合(約40%)がエラーを検査し、除去しているが、UNIXシステムの方法はエラーを慎重に処理している.すなわち、statのようなCでメソッドを呼び出すと、ドキュメントにはすべての失敗がリストされます.ユーザーは、プログラムでどの状況を修復すべきか、どの致命的なエラーをさらに処理すべきかを簡単に選択できます(extsmailでは、メモリ不足が致命的なエラーです).これは思考モードの上で言語の異常な処理方式の巨大な相違点に基づいて、経典の哲学は正常にコードを書くので、少数の情況の下でtry ... catch文のブロックを書いて特定の誤り(めったに出会う誤り)を処理します.Javaは、制御された例外で、「このメソッドを呼び出すときにtry catchの特定の例外が必要です」と異なる方法でユーザーに伝えます.
ソフトウェアの十分な強さ(ロバスト性)を望む場合、異常に基づくソフトウェア設計は適切ではないことが分かった.一つの方法が返す誤りや異常を明確に知り、状況に応じて処理する必要がある.現在のIDEでは,書き方によってどのような異常が投げ出されるかを自動的に表示することができ,せいぜいそれしかできない.理論的には、オブジェクト向けのサブクラスとマルチステートは、プリコンパイルされたライブラリが書かれたコードに基づいて異常を投げ出すかどうかを決定できないことを意味します(サブクラスはメソッドを書き換え、異なるエラーを投げ出すためです).実用的な面から言えば、こんなに多くの方法が多くの異なる異常を投げ出すのではないかと疑っています.これはユーザーを混乱させます.UNIXのメソッドと比較すると、ユーザーに返されるエラーの数を最小限に抑えたり、内部エラーを収集したりすることに注意してください.さらに,異常処理に依存する多くのライブラリが,合理的な数値まで放出される異常数を減らすために大幅な書き換えが必要であることも疑問である.さらに、方法の呼び出し者は、どのようなエラーが二次的で、回復可能で、どのような重要な問題を引き起こし、プログラムの終了を招くかを決定しなければならない.制御された異常,呼び出し者に強制的に処理された異常は,この点を忘れている.
ヘンリー・スペンサーは「UNIXを知らない人はかわいそうに車輪を再発明する運命にある」と話した.これは、Cで書かれたプログラムが私たちが提案した偏見よりも堅固である理由です.UNIX文化は、コンピュータの主流の中で、最も古く、最も賢明な文化で、Cの限界と欠陥を優位にする方法がたくさん発見されています.私が経験したように、ゆっくりと私はこの点を理解しました.以上、大量の思考を経なければ、Cを使うことをお勧めしません.Cを使うと、最終的なソフトウェアは磐石のように丈夫ですが、開発には多くの人力がかかります.
Source:http://tratt.net/laurie/blog/entries/how_can_c_programs_be_so_reliable