5

C および C++ プログラマーは、特に文字列に対して、適切な境界チェックを頻繁に実行できないことで、過去 10 年ほどの間、打撃を受けてきました。これらの障害は、多くの場合、主要なソフトウェア製品に重大なセキュリティ上の問題を引き起こしています。バッファ オーバーフローの危険性が十分に理解されるようになってから、適切な境界チェックを導入しようとする動きにより、多くのプログラマが従来のバッファおよび文字列操作関数などから遠ざかりましstrcpy()sprintf()。これは、これらの関数がバッファ オーバーフローの問題を引き起こす傾向があるためです。ターゲット バッファのサイズに関する仮定。std::stringや などの STL 型の利点の 1 つは、std::vectorバッファー アクセスの強力な制御です。

しかし、1つのことが私を困惑させます。C++ ヘッダーで最も広く使用されている関数の多くは、<algorithms>オーバーフローの悪用を積極的に求めているようです。具体的にはbegin、対応する反復子なしで反復子 (特に InputIterator)を取る関数ですend。例えば:

template <class InputIterator, class OutputIterator>
  OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result);

template <class InputIterator, class OutputIterator, class UnaryOperation>
  OutputIterator transform (InputIterator first1, InputIterator last1,
                            OutputIterator result, UnaryOperation op);

template <class ForwardIterator1, class ForwardIterator2>
   bool is_permutation (ForwardIterator1 first1, ForwardIterator1 last1,
                        ForwardIterator2 first2);

最後の例 — <code>is_permutation() は特に有益です。copy()transform()はよく理解されているため、C++ プログラマー、これらの関数を呼び出す前に出力コンテナーの境界を手動でチェックするかback_inserter必要に応じて出力コンテナーが大きくなるようにする a のようなものを使用することを知っておく必要があります。したがって、と は誤用される可能性がcopy()ありtransform()ますが、何でも可能であり、プログラマーはこれらのような関数のベスト プラクティスについて簡単に教育されます。

is_permutation()はよりトリッキーなケースです。上記の関数宣言を見るだけで、2 番目の範囲 ( で始まる範囲) のサイズについてどう思いますfirst2か? 2 番目の範囲は、最初の範囲と同じサイズである必要がありますか? これらの質問に対する簡単な答えが思い浮かばないことは間違いありません。「順列」の概念は、ほとんどのプログラマーにとって、コピーの概念ほど快適ではなく、なじみがありません。したがって、is_permutation()間違いを犯したり、何らかの方法でバッファをオーバーフローさせたりするのは比較的簡単に思えます。

"調べる!" 私はあなたが言うことを聞きます。はい、もちろんです。しかし、プログラマーが覚えておくべきことをすべて覚えていて、他のすべてを調べていれば、バグやセキュリティ ホールは発生しないのではないでしょうか?

ではis_permutation()、同様の関数 (つまり、すべての入力反復子を受け取るが、すべての範囲に対して完全な開始と終了の反復子のペアを取得しない関数) では、すべての入力範囲に対して完全な開始と終了のペアを必要としないのはなぜでしょうか? lexicographical_compare()(たとえば、この要件を満たしていることに注意してください。) のような関数is_permutation()は、私が想像しているほど実際には危険ではありませんか?

4

3 に答える 3

9

ほとんどの言語は本質的に安全ではなく、正しく使用するかどうかはプログラマ次第です。プログラマーは、関数を呼び出す前に、使用されている引数が正しいかどうかを知る必要があります。

さらに、場合copyによっては、開いている範囲で前方反復子を使用できるようになります。例えば:

std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout," "));

ストリームの終わりをマークするための対応する反復子はなく、ストリームには実際には終わりがなく、継続的に追加し続けることができます。

于 2013-07-10T23:09:15.267 に答える
7

C++14 では、正確にこの点に対処するために、equalの反復子バージョンが 4 つあります。is_permutationmismatch

于 2013-07-11T01:26:30.377 に答える
1

の 2 番目の範囲に最後の反復子を導入するis_permutationと、関数が扱いにくくなるかどうかはわかりません。もっとややこしくなると思います。

順列の問題は、セマンティクスが名前自体にあるということです。あるシーケンスが別のシーケンスの順列であることを確認するには、最後の反復子のないシーケンスが少なくとも最初のシーケンスと同じ長さであることを期待します。

そうでない場合はis_permutation、順列ではないため、呼び出す必要はありません。それよりも長い場合、最初のシーケンスの長さを超えて反復することはないと予想されますが、なぜそうなるのでしょうか? そうではありません - そしてそれはあなたが期待したことなので、信仰が失われることはありません.

C++ では、プログラマーが基本的な予防策を講じることを期待しており、多くの場合、境界チェックの責任をプログラマーに負わせています。その制御をプログラマーに任せないと、言語の力は弱まります。呼び出している場合、順列とは何かis_permutation知っているので、2 番目のイテレータがオーバーフローしないことがわかります。無意味な境界チェックを行ってサイクルを無駄にしたくないのは確かです。

「大きな力には大きな責任が伴う」という古いことわざが当てはまると思います。それは十分に公平ですね。

于 2013-07-10T23:22:15.457 に答える