为什么我的缓冲区占用的字节数超过了允许的字节数

Why does my buffer take more bytes than allowed?

本文关键字:字节数 过了 我的 为什么 缓冲区      更新时间:2023-10-16

我将stringstream的缓冲区设置为5字节的缓冲区。只有当我调用sputn时,它才能读取比我想要的更多的字符。为什么会这样?

#include <iostream>
#include <sstream>
int main()
{
    std::stringstream ss;
    char buf[5];
    ss.rdbuf()->pubsetbuf(buf, sizeof buf);
    ss.rdbuf()->sputn("hello world", 12);
    std::cout << ss.rdbuf(); // prints "Hello world"
}

首先,注意pubsetbuf是实现定义的。在gcc上,它设置了一个新的缓冲区,但例如在MSVC上,什么都不发生(它调用基类setbuf,它什么都不做)。

现在,如上所述,sputn调用溢出(或通过其他方式实现调用溢出的效果):

如果放置区域变满(pptr()==epptr()),此函数可能调用overflow(),或者通过一些其他未指明的方式。

现在根据文档溢出:

确保放置区域至少有一个字符的空间通过保存从pbase()开始的一些初始字符子序列并更新指向输出区域的指针(如果需要)。如果ch不是tracts::eof()(即tracts:eq_int_type(c,traits::of())!=true),则将其放入输出区域或直接保存到输出序列。

该函数可以更新pptr、epptr和pback指针,以定义写入更多数据的位置。一旦出现故障,该功能将确保pptr()==nullptr或pptr(()==epptr。

基本上,这意味着可以适当地调整缓冲区的大小,以适应更多的数据,而对于gcc,这正是正在发生的事情。以下是从这里获得的实际代码:

const __size_type __opt_len = std::max(__size_type(2 * __capacity), __size_type(512));
const __size_type __len = std::min(__opt_len, __max_size);

正如您所看到的,它要么将容量增加一倍,要么将其设置为512的大小,直到达到字符串缓冲区可以达到的最大大小。

C/C++不做任何显式边界检查,因此溢出内存是可能的(而且很容易做到)。如果您通过像Valgrind这样的调试器运行代码,它会告诉您正在读取未初始化的内存。

您的缓冲区仍然有5个字节长,占用的字节数不会超过允许的字节数,但放入12个字节将"只是"执行边界外写入,这可能会导致软件编程中的许多问题(崩溃、UB、数据损坏…)

strlen可以用于在复制之前根据缓冲区大小检查您所写的内容。