我已经用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
答案 0 :(得分:16)
是什么阻止我写入超过81个单元的内存位置?
无。但是,这样做会导致未定义的行为。这意味着任何都可能发生,你不应该依赖它做两次相同的事情。 99.999%的时间这是一个错误。
我该怎么做才能防止这种情况?
在访问(读取或写入)它们之前,请务必检查指针是否在范围内。在传递给字符串函数时,始终确保字符串以\0
结尾。
您可以使用valgrind等调试工具来帮助您找到与越界指针和数组访问相关的错误。
对于您的代码,您可以使utstrncat
的行为类似于utstrcat
,但需要最大大小(即缓冲区的大小)。
您还可以在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_size
和utset_buffer_size
,以便您可以更轻松地进行更改。
答案 1 :(得分:3)
没有什么能阻止你这样做。如果你这样做,任何事情都可能发生:程序可以继续它的快乐方式,好像什么也没发生,它可能会崩溃,它可能会崩溃,它甚至可能会擦掉你的硬盘。这是未定义行为的领域。
有许多工具试图检测或缓解这些类型的问题,但没有什么是万无一失的。其中一个工具是valgrind。 valgrind监视程序的内存访问模式,并通知您这类问题。它通过在各种虚拟机中运行程序来实现这一点,因此它会显着损害程序的性能,但它可以帮助您在正确使用时捕获大量错误。
答案 2 :(得分:0)
没有什么能阻止你超越那个界限,发生的事情取决于超出界限的东西。黑客程序的标准黑客技巧(缓冲区溢出),不检查并确保它们不会覆盖缓冲区限制。
正如其他海报所提到的,你只需要仔细编程。不要使用像strlen,strcpy这样的调用 - 使用像strncpy等长度限制的反面词。
答案 3 :(得分:0)
Carl建议 strncpy(),这是一个正确方向的开始。主要思想是通过采用特定的做法养成避免缓冲区溢出的习惯。 strlcpy and strlcat--Consistent, Safe, String Copy and Concatenation中介绍了一个更为深思熟虑的图书馆。
答案 4 :(得分:-4)
会发生什么:没有,或者你的程序会让SIGSEGV被抛出。 你应该做什么:仔细编写你的程序。使用像valgrind这样的工具。