C++字符串是否会发生缓冲区溢出?

5
这篇文章是关于C++中的字符串。我很久没有碰过C/C++了;事实上,我只在大学的第一年学习了这些语言,已经有7年了。
在C中,要存储字符串,我必须创建字符数组(无论是静态还是动态,都不重要)。因此,这意味着我需要提前猜测数组将包含的字符串的大小。在C++中,我采用了同样的方法。我知道有一个std::string类,但我从未使用过它。
我的问题是,由于我们从未声明std::string类中数组/字符串的大小,当写入时是否会发生缓冲区溢出。我的意思是,在C中,如果数组的大小为10,而我在控制台上输入了超过10个字符,则额外的数据将被写入到其他对象的内存位置中,该位置与数组相邻。在使用cin对象时,std::string是否会发生类似的情况。
在C++中,使用std::string时,我需要提前猜测字符串的大小吗?
感谢你们所有人。这个页面上没有一个正确的答案(提供了许多不同的解释),所以我不会选择任何一个作为唯一的答案。我对前5个回答感到满意。注意保持安全!

那么我不需要事先猜测字符串的大小吗? - Jazz
6个回答

9

根据您用于访问string对象的成员而定,如果使用reference operator[](size_type pos),其中pos>size(),则会发生这种情况。


6
假设标准库实现没有错误,std::string总是管理自己的内存。除非你破坏了std::string提供的访问器方法,像这样做: ``` std::string s("hello"); char* p = &s[0]; // 指向 std::string 的内部缓冲区 ```
std::string str = "foo";
char *p = (char *)str.c_str();
strcpy(p, "blah");

在这里你没有任何保护,而且正在触发未定义行为


那么只有从 C 派生的函数才会引起问题吗? - Jazz
@Jazz:好的,dirkgently在他的答案中给了另一个例子。 - Oliver Charlesworth
2
没有强制类型转换,编译器至少会检测到类型不匹配。修改 const charT* c_str() const; 返回的指针是未定义行为。这是 c_str() 明确规定的要求:要求:程序不得更改字符数组中存储的任何值 - dirkgently

3
std::string通常可以防止缓冲区溢出,但仍有可能因编程错误导致缓冲区溢出。虽然C++通常会在操作引用字符串边界外的内存时抛出out_of_range异常,但下标运算符[](不执行边界检查)不会抛出异常。
另一个问题发生在将std::string对象转换为C风格字符串时。如果使用string::c_str()进行转换,则会得到一个正确的空终止C风格字符串。但是,如果使用string::data(),该方法直接将字符串写入数组(返回指向数组的指针),则会得到一个未以空字符结尾的缓冲区。c_str()和data()之间唯一的区别在于c_str()会添加一个尾随的空字节。
最后,许多现有的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字节的位置(buffer)。额外的字节超出了缓冲区并覆盖了为FP、返回地址等分配的空间,这反过来破坏了进程堆栈。用于复制字符串的函数是strcpy,它没有完成任何边界检查。使用strncpy可以防止堆栈的这种损坏。然而,这个经典的例子表明,缓冲区溢出可以覆盖函数的返回地址,从而改变程序的执行路径。请记住,函数的返回地址是内存中下一条指令的地址,该指令在函数返回后立即执行。

这里有一个好教程,可以给你满意的答案。


但是楼主正在询问关于std::string的问题。 - Oliver Charlesworth

2

C++中,std::string类从最小尺寸开始(或您可以指定起始尺寸)。如果超过该尺寸,则std::string会分配更多的动态内存。


1
“C++代码会发生缓冲区溢出吗?”
在很大程度上,只要C程序是合法的C++代码(它们几乎都是),并且C程序存在缓冲区溢出问题,那么C++程序也可能存在缓冲区溢出问题。
作为比C更加丰富的语言,我相信C++可以以C无法做到的方式发生缓冲区溢出问题 :-}

1
假设提供std::string的库已经正确编写,您无法通过向std::string对象添加字符来导致缓冲区溢出。
当然,库中存在漏洞也是有可能的。

1
更准确地说(但我认为您的答案是发布者正在寻找的),缓冲区溢出将通过std :: bad_alloc异常表现出来,而不是通过损坏的内存。 而且,您需要生成一个相当大的字符串才能发生这种情况。 - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接