2

为什么以下工作不会引发某种分段错误?

char *path = "/usr/bin/";
char *random = "012";

// path + random + \0
// so its malloc(13), but I get 16 bytes due to memory alignment (im on 32bit)
newPath = (char *) malloc(strlen(path) + strlen(random) + 1);

strcat(newPath, path);
strcat(newPath, "random");
// newPath is now: "/usr/bin/012\0" which makes 13 characters.

但是,如果我添加

strcat(newPath, "RANDOMBUNNIES");

这个调用不应该失败,因为 strcat 使用的内存比分配的多吗?因此,不应该

free(newPath)

也失败了,因为它试图释放 16 个字节,但我使用了 26 个字节(“/usr/bin/012RANDOMBUNNIES\0”)?

非常感谢您!

4

9 回答 9

7

大多数情况下,这种溢出问题不会使您的程序在烟雾和烧焦的硫磺味中爆炸。更微妙的是:在溢出变量之后分配的变量将被更改,导致程序稍后出现无法解释且看似随机的行为。

于 2011-07-16T15:46:20.883 回答
3

整个程序片段是错误的。您假设malloc()返回的内容至少将第一个字节设置为0. 通常情况并非如此,因此即使您的“保险箱”strcat()也是错误的。

但除此之外,正如其他人所说,未定义的行为并不意味着您的程序会崩溃。这只意味着它可以做任何事情(包括崩溃,但如果你不走运,也不会崩溃)。

(另外,您不应该转换 . 的返回值malloc()。)

于 2011-07-16T16:03:53.543 回答
1

分段错误通常是由于访问无效的内存段而发生的。在这里它不会给出错误(Segmentation fault),因为您仍然可以访问内存。但是,您正在覆盖其他未定义行为的内存位置,您的代码运行良好。

于 2011-07-16T20:34:44.207 回答
1

写入比 malloced 更多的字符是未定义的行为
未定义的行为意味着任何事情都可能发生并且行为无法解释。

于 2011-07-16T15:49:32.407 回答
0

操作系统在我的系统上以一定的粒度分配 4kb 的页面大小(这在 32 位机器上是典型的), malloc() 是否总是从操作系统获取新页面取决于您的C 运行时库

于 2011-07-16T15:51:48.977 回答
0

它会失败并且不会随机失败,具体取决于 malloc 内存之后的内存可用性。

此外,当您想随机连接时,您不应该加上引号。那应该是

strcat(newPath, random);
于 2011-07-16T15:46:22.407 回答
0

许多 C 库函数不检查它们是否溢出。由程序员来管理分配的内存。您可能只是在内存中写入另一个变量,对程序的操作产生不可预测的影响。C 是为提高效率而设计的,而不是为了指出编程中的错误。

于 2011-07-16T15:46:43.217 回答
0

你有这个电话的运气。您不会收到段错误,因为您的调用可能停留在地址空间的分配部分中。这是未定义的行为。不保证不会覆盖已写入内容的最后一个字符。此调用也可能失败。

于 2011-07-16T15:46:51.937 回答
0

不保证缓冲区溢出会导致段错误。行为只是未定义的。您可能会一次成功地写入不属于您的内存,另一次导致崩溃,第三次默默地覆盖完全不相关的内容。其中哪一种发生取决于操作系统(和操作系统版本)、硬件、编译器(和编译器标志)以及系统上运行的几乎所有其他东西。

这就是缓冲区溢出如此令人讨厌的错误来源的原因:通常,明显的症状会在生产中显示出来,但在通过调试器运行时不会;并且症状通常不会显示在它们起源的程序部分中。当然,它们是一个受欢迎的漏洞,可以注入您自己的代码。

于 2011-07-16T15:50:04.887 回答