std::string 通常可以防止缓冲区溢出,但仍然存在编程错误可能导致缓冲区溢出的情况。当操作引用超出字符串边界的内存时,C++ 通常会抛出 out_of_range 异常,而下标运算符 [](不执行边界检查)则不会。
将 std::string 对象转换为 C 风格的字符串时会出现另一个问题。如果你使用 string::c_str() 进行转换,你会得到一个正确的以 null 结尾的 C 样式字符串。但是,如果您使用 string::data(),它将字符串直接写入数组(返回指向数组的指针),您将获得一个非空终止的缓冲区。The only difference between c_str() and data() is that c_str() adds a trailing null byte.
最后,许多现有的 C++ 程序和库都有自己的字符串类。要使用这些库,您可能必须使用这些字符串类型或不断地来回转换。在安全性方面,此类库的质量参差不齐。通常最好使用标准库(如果可能)或了解所选库的语义。一般而言,应根据库的使用难易程度、可能发生的错误类型、这些错误发生的难易程度以及可能产生的潜在后果来评估库。参考https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/295-BSI.html
在 c 中,原因解释如下:
void function (char *str) {
char buffer[16];
strcpy (buffer, str);
}
int main () {
char *str = "I am greater than 16 bytes"; // length of str = 27 bytes
function (str);
}
该程序肯定会导致意外行为,因为 27 字节的字符串 (str) 已复制到仅分配 16 字节的位置(缓冲区)。额外的字节越过缓冲区并覆盖为 FP 分配的空间、返回地址等。这反过来又会破坏进程堆栈。用于复制字符串的函数是 strcpy,它不完成边界检查。使用 strncpy 可以防止这种堆栈损坏。然而,这个经典的例子表明缓冲区溢出会覆盖函数的返回地址,进而改变程序的执行路径。回想一下,函数的返回地址是内存中下一条指令的地址,该指令在函数返回后立即执行。
这是一个很好的教程,可以让您的答案满意。