【发布时间】:2013-07-10 23:03:03
【问题描述】:
在过去十年左右的时间里,C 和 C++ 程序员因经常无法执行正确的边界检查而受到打击,尤其是在字符串上。这些故障常常导致主要软件产品出现严重的安全问题。由于缓冲区溢出的不安全性已被充分理解,建立适当边界检查的驱动力已将许多程序员推离了传统的缓冲区和字符串操作函数,如 strcpy() 和 sprintf(),至少部分原因是这些函数倾向于通过假设目标缓冲区的大小来引发缓冲区溢出问题。 std::string 和 std::vector 等 STL 类型的优点之一是它们对缓冲区访问的强大控制。
但有一件事让我很困惑。 <algorithms> C++ 标头中的许多最广泛使用的函数似乎都在恳求溢出滥用:特别是那些采用 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);
最后一个例子——is_permutation() 特别有指导意义。 copy() 和 transform() 很容易理解,因此 C++ 程序员应该知道在调用这些函数之前手动检查输出容器的边界或使用某些东西就像 back_inserter 一样,它确保输出容器根据需要增长。因此,可以证明尽管copy() 和transform() 可以被误用,但任何东西都可以,而且程序员很容易就这些函数的最佳实践进行培训。
is_permutation() 是一个更棘手的案例。看看上面的函数声明,你会假设第二个范围的大小(以first2 开头的那个)?第二个范围是否需要与第一个范围相同,或者不更小,或者不更大?我敢打赌,这些问题的简单答案不会浮现在您的脑海中。对于大多数程序员来说,“排列”的概念不如复制的概念那么舒服和熟悉。因此,is_permutation() 错误并以一种或另一种方式溢出缓冲区似乎相对容易。
“查一下!”我听你说。是的,当然。但是,如果程序员记住他们应该记住的所有内容并查找其他所有内容,那么我们就不会有错误和安全漏洞,对吗?
那么,为什么 is_permutation() 和类似的函数(即函数采用所有输入迭代器但不是每个范围的完整开始-结束迭代器对)不需要所有输入范围的完整开始-结束对? (请注意 lexicographical_compare(),例如,确实 满足此要求。)像 is_permutation() 这样的函数实际上并没有我想象的那么不安全吗?
【问题讨论】:
标签: c++ algorithm security stl