直到最近,我一直都不需要将strdup(stringp)
与strsep(&stringp_copy, token)
一起使用,我认为这会导致内存泄漏。
(strdup()
总是free
'就好了。)
我修复了漏洞,我想我明白了,但我无法弄明白为什么需要。
原始代码(摘要):
const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *line, *field_name;
int colon_position;
message_copy = strdup(message);
while(line = strsep(&message_copy, "\n")) {
printf(line);
char *colon = strchr(line, ':');
if (colon != NULL) {
colon_position = colon - line;
strncpy(field_name, line, colon_position);
printf("%s\n", field_name);
}
}
free(message_copy);
不泄漏的新代码:
const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *freeable_message_copy, *line, *field_name;
int colon_position;
freeable_message_copy = message_copy = strdup(message);
while(line = strsep(&message_copy, "\n")) {
printf(line);
char *colon = strchr(line, ':');
if (colon != NULL) {
colon_position = colon - line;
strncpy(field_name, line, colon_position);
printf("%s\n", field_name);
}
}
free(freeable_message_copy);
如何在第一个代码中覆盖message_copy
指针?或者是吗?
答案 0 :(得分:10)
函数strsep()接受一个指向原始字符串(message_copy)的指针并修改它以返回一个指向'next'标记的新指针
const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *original_copy;
//here you have allocated new memory, a duplicate of message
message_copy = original_copy = strdup(message);
在这里打印指针,
printf("copy %p, original %p\n", message_copy, original_copy);
请注意,当您使用strsep()时,您正在修改message_copy,
char* token;
//here you modify message_copy
while(token = strsep(&message_copy, "\n")) {
printf("%s\n", token);
}
这说明了更改后的message_copy,而original_copy未更改,
printf("copy %p, original %p\n", message_copy, original_copy);
由于message_copy没有指向原始的strdup()结果,这是错误的,
free(message_copy);
但保持原始的strdup()结果,这个免费的作品
//original_copy points to the results of strdup
free(original_copy);
答案 1 :(得分:5)
因为strsep()
修改了message_copy
参数,所以你试图释放malloc()
等未返回的指针。这会产生来自某些malloc()
图书馆和valgrind
的投诉。它也是未定义的行为,通常会在短时间内导致崩溃(但代码崩溃的位置与执行损坏的代码无关的不方便)。
实际上,你的循环迭代直到message_copy
设置为NULL,因此你释放NULL,这是定义的安全行为,但它也是一个无操作。它没有释放通过strdup()
分配的指针。
要点:
答案 2 :(得分:1)
阅读strsep
手册页here。
简而言之,strsep
函数将修改传递给函数的原始字符指针,用\0
覆盖分隔符的每个出现位置,然后更新原始字符指针以指向经过\0
。
你的第二个版本没有泄漏,因为你创建了一个临时指针指向从strdup()
返回的原始字符指针的开头,所以内存被正确释放,就像你调用free()
一样使用原始的char指针而不是strsep()
已修改的更新的指针。
答案 3 :(得分:0)
从手册页
...通过使用空字节('\ 0')和*stringp is updated to point past the token
覆盖分隔符来终止此令牌....