You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用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函数的行为理解不到位:

  1. 无效free的原因:
    dirname的返回值分两种情况:
  • 若输入路径包含目录部分,它返回指向输入字符串内部的指针(也就是strdup分配内存里的某个偏移位置)
  • 若输入是./或单个文件名这类无上级目录的路径,它返回指向静态存储区的字符串(比如Valgrind提示的dot.0,就是静态存储的.字符)

你现在free(temp)时,temp是第二次dirname的返回值,它要么是原始堆内存的偏移指针,要么是静态存储区的地址——这两种情况调用free都是未定义行为,后者直接触发"Invalid free"错误。

  1. 内存泄漏的原因:
    你只保存了第二次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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 03:35:24