如果我尝试访问malloc()区域以外的内存会发生什么?

我用char* memoryChunk = malloc ( 80* sizeof(char) + 1);分配了一个内存char* memoryChunk = malloc ( 80* sizeof(char) + 1); 是什么阻止我写入超过81个单元的内存位置? 我该怎么做才能防止这种情况发生?

 void testStage2(void) { char c_str1[20] = "hello"; char* ut_str1; char* ut_str2; printf("Starting stage 2 tests\n"); strcat(c_str1, " world"); printf("%s\n", c_str1); // nothing exciting, prints "hello world" ut_str1 = utstrdup("hello "); ut_str1 = utstrrealloc(ut_str1, 20); utstrcat(ut_str1, c_str1); printf("%s\n", ut_str1); // slightly more exciting, prints "hello hello world" utstrcat(ut_str1, " world"); printf("%s\n", ut_str1); // exciting, should print "hello hello world wo", 'cause there's not enough room for the second world } char* utstrcat(char* s, char* suffix){ int i = strlen(s),j; int capacity = *(s - sizeof(unsigned) - sizeof(int)); for ( j =0; suffix[j] != '\0'; j++){ if ((i+j-1) == 20) return s; s[i+j] = suffix[j]; } //strcpy(s, suffix); s[i + j] = '\0'; return s; }// append the suffix to s 

是什么阻止我写入超过81个单元的内存位置?

没有。 但是,这样做会导致未定义的行为 。 这意味着任何事情都可能发生,你不应该依赖它做两次相同的事情。 99.999%的时间这是一个错误。

我该怎么做才能防止这种情况发生?

在访问(读取或写入)它们之前,请务必检查指针是否在边界内。 在传递给字符串函数时,始终确保字符串以\0结尾。

您可以使用诸如valgrind之类的调试工具来帮助您找到与越界指针和数组访问相关的错误。

stdlib的方法

对于您的代码,您可以使用utstrncat ,它的作用类似于utstrcat但需要最大大小(即缓冲区的大小)。

stdc ++的方法

您还可以创建数组结构/类或在C ++中使用std::string 。 例如:

 typedef struct UtString { size_t buffer_size; char *buffer; } UtString; 

然后让你的function对它进行操作。 您甚至可以使用此技术进行动态重新分配(但这似乎不是您想要的)。

缓冲结束标记方法

另一种方法是使缓冲区标记结束 ,类似于字符串标记的结尾 。 当您遇到标记时,不要写入该位置或其前面的位置(对于字符串标记的结尾)(或者您可以重新分配缓冲区以便有更多空间)。

例如,如果您将"hello world\0xxxxxx\1"作为字符串(其中\0是字符串标记的结尾, \1是缓冲区标记的结尾, x是随机数据)。 附加" this is fun"将如下所示:

 hello world\0xxxxxx\1 hello world \0xxxxx\1 hello world t\0xxxx\1 hello world th\0xxx\1 hello world thi\0xx\1 hello world this\0x\1 hello world this \0\1 *STOP WRITING* (next bytes are end of string then end of buffer) 

你的问题

您的代码存在问题:

  if ((i+j-1) == 20) return s; 

虽然您在超越缓冲区之前停止,但您没有标记字符串的结尾。

您可以使用break来提前结束for循环,而不是返回。 这将导致for循环后的代码运行。 这将设置字符串标记的结束并返回字符串,这是您想要的。

另外,我担心你的分配可能存在错误。 你有+ 1来分配字符串之前的大小,对吗? 有一个问题: unsigned通常不是1个字符; 你需要+ sizeof(unsigned) 。 我还会编写utget_buffer_sizeutset_buffer_size以便您可以更轻松地进行更改。

没有什么能阻止你这样做。 如果你这样做,任何事情都可能发生:程序可以继续它的快乐方式,好像什么也没发生,它可能会崩溃,它可能会崩溃,它甚至可能会擦掉你的硬盘。 这是未定义行为的领域。

有许多工具试图检测或缓解这些类型的问题,但没有什么是万无一失的。 一个这样的工具是valgrind 。 valgrind监视程序的内存访问模式,并通知您这类问题。 它通过在各种虚拟机中运行程序来实现这一点,因此它会显着损害程序的性能,但它可以帮助您在正确使用时捕获大量错误。

没有什么可以阻止你超越那个界限,发生的事情取决于超出界限的东西。 黑客程序的标准黑客技巧(缓冲区溢出),不检查并确保它们不会覆盖缓冲区限制。

正如其他海报所提到的,你只需要仔细编程。 不要使用像strlen,strcpy这样的调用 – 使用像strncpy这样的长度有限的反面词。

卡尔建议使用strncpy() ,这是一个正确方向的开端。 主要思想是通过采用特定的做法养成避免缓冲区溢出的习惯。 strlcpy和strlcat涵盖了一个更为深思熟虑的库- 一致,安全,字符串复制和连接 。

会发生什么:没什么,或者你的程序会得到SIGSEGV。 你应该做什么:仔细编写你的程序。 使用像valgrind这样的工具。