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

C语言cURL write callback内存泄漏问题定位与解决求助

问题分析与解决

内存泄漏的核心原因

你的代码存在两处直接导致内存泄漏的问题,以及一处潜在内存安全风险:

1. 未释放request函数返回的动态内存

request函数通过malloc(1)初始化输出缓冲区,后续又通过realloc扩容,最终返回这块内存。但调用request()后,你仅保存了指针const char* out,从未调用free(out)释放这块内存——这就是valgrind报告中realloc相关内存泄漏的直接原因。

2. 未清理cURL资源

request函数中调用curl_easy_init()创建了cURL句柄,但没有调用curl_easy_cleanup(curl)释放该句柄;即使header变量初始化为NULL,也应该调用curl_slist_free_all(header)(该函数对NULL输入是安全的),这部分未清理的资源也会导致额外内存泄漏。

3. writecallback的内存安全风险(间接引发泄漏)

writecallback中直接用*stream = (char*)realloc(*stream, tsize+1);,若realloc失败返回NULL,会覆盖原*stream指针,导致之前分配的内存永久丢失,同时程序会因访问NULL指针崩溃。

修复方案

1. 释放返回的动态内存

在使用完out指向的内容后,必须调用free释放:

const char* out = request();
// 业务处理逻辑
free((void*)out); // 因out是const char*,需强制转换为void*

2. 完善cURL资源清理与错误处理

修改request函数,确保资源在任何分支下都能被清理:

char* request(){
    CURL* curl = curl_easy_init();
    if (!curl) { // 增加cURL初始化失败的判断
        return NULL;
    }
    struct curl_slist* header = NULL;

    char* output = malloc(1);
    if (!output) { // 增加malloc失败的判断
        curl_easy_cleanup(curl);
        return NULL;
    }
    output[0] = '\0';
    
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &output);
    
    CURLcode res = curl_easy_perform(curl);
    if(res != CURLE_OK){
        printf("Failed performing actions,\n%s\n", curl_easy_strerror(res));
        free(output); // 请求失败时也要释放已分配的内存
        output = NULL;
    }

    // 无条件清理cURL资源
    curl_slist_free_all(header);
    curl_easy_cleanup(curl);
    
    return output;
}

3. 修复writecallback的内存安全问题

先保存旧指针,避免realloc失败丢失内存:

static size_t writecallback(char* contents, size_t size, size_t nmemb, char** stream) {
    size_t csize = size * nmemb;
    if (csize == 0) {
        return 0; // 无数据可写,直接返回
    }

    size_t psize = strlen(*stream);
    size_t tsize = csize + psize;

    // 先分配新内存,保存旧指针防止丢失
    char* temp = (char*)realloc(*stream, tsize + 1);
    if (!temp) {
        return 0; // 返回0告知cURL分配失败
    }

    *stream = temp;
    memcpy(*stream + psize, contents, csize);
    (*stream)[tsize] = '\0';
    return csize;
}

总结

  • 内存泄漏本质是分配的内存/资源未被释放:包括你自己管理的输出缓冲区,以及cURL创建的句柄资源。
  • 编写C语言代码时,要严格遵循谁分配谁释放的原则,所有创建的资源都必须对应清理。
  • 动态内存操作(如realloc)必须考虑失败场景,避免丢失原指针导致内存泄漏。

内容的提问来源于stack exchange,提问作者Lime Stone

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 18:57:32