c - 如果我尝试访问超出 malloc() 区域的内存,会发生什么情况?

标签 c memory-management malloc

我用 char* memoryChunk = malloc ( 80* sizeof(char) + 1); 分配了一 block 内存是什么阻止我写入超过 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

最佳答案

What is keeping me from writing into the memory location beyond 81 units?

没有。但是,这样做会导致未定义的行为。这意味着任何事情 都可能发生,您不应该依赖它重复做同样的事情。 99.999% 的情况下这是错误。

What can I do to prevent that?

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

您可以使用valgrind等调试工具来协助您定位与越界指针和数组访问相关的错误。

stdlib 的方法

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

stdc++的方法

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

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

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

缓冲区结束标记方法

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

例如,如果您将 "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 以便您可以更轻松地进行更改。

关于c - 如果我尝试访问超出 malloc() 区域的内存,会发生什么情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1655971/

相关文章:

c++ - void*字面意思是float,怎么投?

c - 瓦拉内存管理

c++ - 为什么在这个函数中分配内存需要一个指向指针的指针?

c++ - malloc 的类型转换返回什么?

c - 冲洗替代品

c - 列出目录内容,如 Unix 'find' 命令

c++ - c/c++中perl的hash变量替换

java - 管理内存中非常大的 xml

C# 内存使用过多

c++ - Malloc 在 main() 或任何其他函数之外(即在全局范围内)