调用free()释放strdup初始化的变量仍存在内存泄漏问题
内存泄漏与无效free问题排查
我编写了如下代码:
static const char * path[2]; int main(int argc, char *argv[]) { // validate argument char * temp = dirname(dirname(strdup(argv[optind]))); path[0] = temp; path[1] = NULL; // do stuff free(temp); return 0; }
我知道strdup会分配内存,需要调用free()避免内存泄漏。我在函数返回前执行了free,但泄漏依然存在,同时还出现了无效free的错误。
Valgrind输出:
$ valgrind --leak-check=full -s ./tstprog meta_schema.schema ==36849== Memcheck, a memory error detector ==36849== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==36849== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info ==36849== Command: ./tstprog meta_schema.schema ==36849== ==36849== Invalid free() / delete / delete[] / realloc() ==36849== at 0x484827F: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==36849== by 0x11577A: main (tstprog.c:134) ==36849== Address 0x4a42ae1 is 0 bytes inside data symbol "dot.0" ==36849== ==36849== ==36849== HEAP SUMMARY: ==36849== in use at exit: 19 bytes in 1 blocks ==36849== total heap usage: 255 allocs, 255 frees, 64,111 bytes allocated ==36849== ==36849== 19 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==36849== at 0x4845899: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==36849== by 0x49240CF: strdup (in /usr/lib/libc.so.6) ==36849== by 0x1155C1: main (tstprog.c:108) ==36849== ==36849== LEAK SUMMARY: ==36849== definitely lost: 19 bytes in 1 blocks ==36849== indirectly lost: 0 bytes in 0 blocks ==36849== possibly lost: 0 bytes in 0 blocks ==36849== still reachable: 0 bytes in 0 blocks ==36849== suppressed: 0 bytes in 0 blocks ==36849== ==36849== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) ==36849== ==36849== 1 errors in context 1 of 2: ==36849== Invalid free() / delete / delete[] / realloc() ==36849== at 0x484827F: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==36849== by 0x11577A: main (tstprog.c:134) ==36849== Address 0x4a42ae1 is 0 bytes inside data symbol "dot.0" ==36849== ==36849== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
我查过相关问题,里面调用free的方式和我看起来一样,请问我忽略了什么?
问题根源
你犯了两个关键错误,核心是对dirname函数的行为理解不到位:
- 无效free的原因:
dirname的返回值分两种情况:
- 若输入路径包含目录部分,它返回指向输入字符串内部的指针(也就是
strdup分配内存里的某个偏移位置) - 若输入是
./或单个文件名这类无上级目录的路径,它返回指向静态存储区的字符串(比如Valgrind提示的dot.0,就是静态存储的.字符)
你现在free(temp)时,temp是第二次dirname的返回值,它要么是原始堆内存的偏移指针,要么是静态存储区的地址——这两种情况调用free都是未定义行为,后者直接触发"Invalid free"错误。
- 内存泄漏的原因:
你只保存了第二次dirname的返回值,但strdup分配的原始指针已经丢失。第一次调用dirname时会修改strdup返回的字符串(把最后一个/后的内容改为\0),但你没保存原始指针,导致后续无法释放这部分堆内存,所以Valgrind提示确定的内存泄漏。
修复方案
必须保存strdup返回的原始指针,仅释放该指针指向的内存,绝对不能去free``dirname的返回值:
static const char * path[2]; int main(int argc, char *argv[]) { // validate argument char * original = strdup(argv[optind]); char * parent_dir = dirname(original); char * grandparent_dir = dirname(parent_dir); path[0] = grandparent_dir; path[1] = NULL; // do stuff free(original); // 仅释放strdup分配的原始堆内存 return 0; }
注意:dirname会修改输入的字符串,所以必须传递可修改的内存(strdup返回的堆内存符合要求),不能直接传递argv[optind](argv的字符串是只读的)。
内容的提问来源于stack exchange,提问作者User3952
相关产品推荐
相关产品推荐

