如果我向12字节缓冲区写入少于12个字节会发生什么?

hex*_*079 28 c c++ buffer memory-management

可以理解的是,将缓冲区错误输出(或创建溢出),但如果12字节缓冲区中使用的字节少于12个,会发生什么?是否有可能或者空尾随时都是0?正交问题可能会有所帮助:缓冲区在实例化但未被应用程序使用时包含哪些内容?

我在Visual Studio中查看了几个宠物程序,似乎它们附加了0(或空字符),但我不确定这是否是一个可能因语言/编译器而异的MS实现.

sel*_*bie 17

采用以下示例(在代码块内,而不是全局):

char data[12];
memcpy(data, "Selbie", 6);
Run Code Online (Sandbox Code Playgroud)

甚至这个例子:

char* data = new char[12];
memcpy(data, "Selbie", 6);
Run Code Online (Sandbox Code Playgroud)

在上述两种情况下,前6个字节的dataS,e,l,b,i,和e.剩下的6个字节data被认为是"未指定的"(可以是任何东西).

是否有可能或者空尾随时都是0?

根本不保证.我所知道的唯一保证零字节填充的分配器是calloc.例:

char* data = calloc(12,1);  // will allocate an array of 12 bytes and zero-init each byte
memcpy(data, "Selbie");
Run Code Online (Sandbox Code Playgroud)

缓冲区实例化但应用程序尚未使用时包含哪些内容?

从技术上讲,根据最新的C++标准,分配器提供的字节在技术上被认为是"未指定的".你应该假设它是垃圾数据(任何东西).不要对内容做任何假设.

使用Visual Studio进行调试构建通常会使用with 0xcc0xcdvalues 初始化缓冲区,但在发布版本中不是这种情况.但是,对于Windows和Visual Studio,有一些编译器标志和内存分配技术可以保证零初始内存分配,但它不可移植.

  • "你应该假设它可以填充随机字节." - 这个答案很好,但我想反对使用"随机"这个词.分配内存然后读取它不是随机性的良好来源. (11认同)
  • "剩余的6个字节的数据是未定义的,但将是一些东西." - 不,这是错的!在未定义的行为中访问未初始化的值.你不能在假设"好吧,那里有东西,我不关心什么,无关紧要"的情况下编写代码.假设未发生对未初始化值的访问,优化器可能会完全重新排列您的代码. (6认同)
  • "剩余的6个字节的'数据'是未定义的,但将是一些东西." 但如果它们未定义,那么试图确定"某事"是不是不明确的行为?所以它并不重要,唯一的解决方案是永远不要读未初始化的内存.这不是"随机性"的情况(特别是不作为RNG); 相反,我会说假设未初始化的数据是*有毒*.读取`char`类型可能有一个例外,它不能有陷阱表示或填充,但它仍然没有意义或好的代码进入读取未初始化部分的情况. (4认同)
  • @Wilson这是一个任意值(虽然很容易在视觉上识别).[不同的值有不同的含义.](/sf/answers/25925371/)原因是在调试期间给开发人员提供了关于出错的提示(或者简单地说,哪些变量尚未初始化). (2认同)

Mat*_*her 11

C++具有存储类,包括全局,自动和静态.初始化取决于如何声明变量.

char global[12];  // all 0
static char s_global[12]; // all 0

void foo()
{
   static char s_local[12]; // all 0
   char local[12]; // automatic storage variables are uninitialized, accessing before initialization is undefined behavior 
}
Run Code Online (Sandbox Code Playgroud)

一些有趣的细节在这里.


Age*_*t_L 11

考虑你的缓冲区,用零填充:

[00][00][00][00][00][00][00][00][00][00][00][00]
Run Code Online (Sandbox Code Playgroud)

现在,让我们写10个字节.值从1开始递增:

[01][02][03][04][05][06][07][08][09][10][00][00]
Run Code Online (Sandbox Code Playgroud)

现在再次,这次,4倍0xFF:

[FF][FF][FF][FF][05][06][07][08][09][10][00][00]
Run Code Online (Sandbox Code Playgroud)

如果在12字节缓冲区中使用少于12个字节会发生什么?是否有可能或者空尾随时都是0?

您可以根据需要进行编写,其余字节保持不变.

正交问题可能会有所帮助:缓冲区在实例化但未被应用程序使用时包含哪些内容?

未指定.预计之前使用此内存的程序(或程序的其他部分)会留下垃圾.

我在Visual Studio中查看了几个宠物程序,似乎它们附加了0(或空字符),但我不确定这是否是一个可能因语言/编译器而异的MS实现.

这正是你的想法.这次有人为你做过这件事,但不能保证它会再次发生.它可能是附加清理代码的编译器标志.某些版本的MSVC用于在调试中运行但不在发布时使用0xCD填充新内存.它也可以是一个系统安全功能,在将内存提供给您的进程之前擦除内存(因此您无法监视其他应用程序).永远记得在重要的地方使用memset初始化缓冲区.最终,如果您依赖新缓冲区来包含某个值,则在自述文件中使用某些编译器标志.

但清洁并不是必需的.你需要一个12字节长的缓冲区.你用7个字节填充它.然后你把它传递到某个地方 - 你说"这里有7个字节".从中读取缓冲区的大小无关紧要.您希望其他函数尽可能多地阅读,而不是尽可能多地阅读.实际上,在C语言中通常无法判断缓冲区的长度.

并附注:

可以理解的是,将缓冲区错误输出(或创建溢出)

它没有,这就是问题所在.这就是为什么它是一个巨大的安全问题:没有错误,程序试图继续,所以它有时执行它从未意图的恶意内容.因此,我们不得不向操作系统添加一堆机制,例如ASLR,这将增加程序崩溃的可能性并降低其继续损坏内存的可能性.因此,永远不要依赖那些事后的守卫并亲自观察你的缓冲区边界.