【问题标题】:Does buffer overflow happen in C++ strings?C++ 字符串中是否发生缓冲区溢出?
【发布时间】:2012-05-01 13:13:44
【问题描述】:

这与 C++ 中的字符串有关。很久没有接触C/C++了;事实上,大约 7 年前,我只在大学的第一年就使用这些语言进行了编程。

在 C 语言中,为了保存字符串,我必须创建字符数组(无论是静态的还是动态的,这都无关紧要)。所以这意味着我需要提前猜测数组将包含的字符串的大小。好吧,我在 C++ 中应用了相同的方法。我知道有一个 std::string 类,但我从来没有使用它。

我的问题是,由于我们从未在 std::string 类中声明数组/字符串的大小,因此在写入时是否会发生缓冲区溢出。我的意思是,在 C 语言中,如果数组的大小为 10,并且我在控制台上输入了超过 10 个字符,那么额外的数据将被写入与数组相邻的其他对象的内存位置。使用 cin 对象时,std::string 中是否会发生类似的事情。

在使用 std::string 时,我是否必须在 C++ 中预先猜测字符串的大小?

好吧!谢谢大家。这个页面上没有一个正确的答案(提供了很多不同的解释),所以我没有选择任何一个这样的答案。我对前 5 个很满意。保重!

【问题讨论】:

  • 这样我就不用事先猜测字符串的大小了吧?

标签: c++ string buffer-overflow


【解决方案1】:

根据您用来访问string 对象的成员,可以。因此,例如,如果您使用 reference operator[](size_type pos) where pos > size(),是的,您会这样做。

【讨论】:

    【解决方案2】:

    假设标准库实现中没有错误,没有。 std::string 总是管理自己的内存。

    当然,除非您颠覆了std::string 提供的访问器方法,并执行以下操作:

    std::string str = "foo";
    char *p = (char *)str.c_str();
    strcpy(p, "blah");
    

    您在这里没有保护,并且正在调用未定义的行为

    【讨论】:

    • 所以只有 C 的派生函数会导致问题?
    • @Jazz:好吧,在他的回答中,很直接地举了另一个例子。
    • 没有强制转换,至少编译器会检测到类型不匹配。修改const charT* c_str() const;返回的指针是UB。这是c_str(): Requires: The program shall not alter any of the values stored in the character array 明确声明的要求。
    【解决方案3】:

    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 可以防止这种堆栈损坏。然而,这个经典的例子表明缓冲区溢出会覆盖函数的返回地址,进而改变程序的执行路径。回想一下,函数的返回地址是内存中下一条指令的地址,该指令在函数返回后立即执行。

    这里有一个good tutorial,可以给你满意的答案。

    【讨论】:

    • 但是 OP 正在询问 std::string
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      假设提供std::string 的库被正确写入,您不会通过向std::string 对象添加字符来导致缓冲区溢出。

      当然,库中的 bug 也不是不可能的。

      【讨论】:

      • 更准确地说(但我认为您的答案是发帖人所要寻找的),缓冲区溢出将通过std::bad_alloc 异常而不是通过损坏的内存来表现出来。你将不得不产生一个相当大的字符串才能发生这种情况。
      【解决方案6】:

      “C++代码中是否发生缓冲区溢出?”

      在某种程度上,C 程序是合法的 C++ 代码(它们几乎都是),并且 C 程序存在缓冲区溢出,C++ 程序也可能存在缓冲区溢出。

      比 C 更丰富,我确信 C++ 可以以 C 不能的方式出现缓冲区溢出:-}

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-10
        • 1970-01-01
        • 2022-11-30
        • 2016-01-15
        • 2013-10-22
        • 2011-02-01
        • 1970-01-01
        • 2011-12-22
        相关资源
        最近更新 更多