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