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

CURL调用代码段错误求助:chunk对象内存被覆盖问题排查

CURL调用API时curl_easy_getinfo导致内存指针失效的问题排查

我写了一段用C语言CURL调用API的代码,运行时触发段错误。通过GDB调试发现错误出在*response = strdup(chunk.memory);这一行,此时chunk对象的memory指针指向不可访问的内存地址:

  • 执行curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res);之前,chunk状态正常,memory存储着预期的JSON响应内容;
  • 执行该行后,chunk的memory指针被覆盖为无效地址(0x557b00000000)。
    chunk是局部变量,找不到被覆盖的原因,请求协助排查。

代码示例

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>

#define API_BASE_PATH "127.0.0.1/api/v2/"
#define API_INFO "lcd/info"

typedef enum {
    Get,                        //!< GET method
    Post,                       //!< POST method
    Patch                       //!< PATCH method
} Api_Method;

struct MemoryStruct {
    char *memory;
    size_t size;
};

size_t WriteData(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    mem->memory = (char*)realloc(mem->memory, mem->size + realsize + 1);
    memset(mem->memory, 0, mem->size + realsize + 1);
    if(mem->memory == NULL) {
        /* out of memory! */
        printf("not enough memory (realloc returned NULL)\n");
        return 0;
    }

    memcpy(&(mem->memory[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->memory[mem->size] = 0;

    return realsize;
}

int callApi(const char* api, char* authorization_token, char* params,
            char* body, char** response, Api_Method method)
{
    CURL* curl;
    CURLcode res;
    MemoryStruct chunk;

    // Initialize objects
    memset(&chunk,0,sizeof(MemoryStruct));
    curl_global_init(CURL_GLOBAL_ALL);
    curl = curl_easy_init();

    // Call the API prepending the base path
    int api_length = strlen(API_BASE_PATH) + strlen(api) + (params != NULL ? strlen(params) : 0) + 1;
    char* api_string = (char*)malloc(api_length);
    memset(api_string, 0, api_length);
    snprintf(api_string, api_length, "%s%s%s", API_BASE_PATH, api, params != NULL ? params : "");

    chunk.memory = (char*)malloc(1);
    chunk.size = 0;

    curl_easy_setopt(curl, CURLOPT_URL, api_string);

    switch (method) {
        case Post:
            curl_easy_setopt(curl, CURLOPT_POST, true);
            break;
        case Patch:
            curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
            break;
        default:
            break;
    }

    // Set the writing callback function
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteData);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
    if ((res = curl_easy_perform(curl)) != CURLE_OK ) {
        printf("curl failed: %s\n", curl_easy_strerror(res));
    } else {
        res = CURLE_OK;
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res);
        curl_easy_cleanup(curl);
        if (response != NULL) {
            *response = strdup(chunk.memory);
        }
    }

    curl_global_cleanup();

    if (chunk.memory != NULL) {
        free(chunk.memory);
    }
    if (api_string != NULL) {
        free(api_string);
    }

    return 0;
}

int main(int argc, char **argv) {
  char* response = NULL;
  // Call the API
  callApi(API_INFO, NULL, NULL, NULL, &response, Get);
  printf("%s\n", response);
  return 0;
}

调试信息

执行curl_easy_getinfo前chunk状态:

{memory = 0x557bcc43a750 "{\"cpf\":\"MYCPF\",\"software_version_tag\":\"1.1.0\",\"di1\":{\"id\":\"DI_1\",\"type\":\"input\",\"status\":0,\"label\":\"D.I. 1\"},\"autologin_enabled\":true,\"data\":{\"min\":0,\"usage\":0,\"eta\":0,\"max\":0},\"acti"..., size = 1920}

执行curl_easy_getinfo后chunk状态:

{memory = 0x557b00000000 <error: Cannot access memory at address 0x557b00000000>, size = 1920}

问题根源

代码存在参数类型不匹配的致命错误:curl_easy_getinfo获取CURLINFO_RESPONSE_CODE时,要求传入long*类型的指针,但你传入的是CURLcode*类型的&res。

在64位系统中,long通常占8字节,而CURLcode本质是int(占4字节)。当curl_easy_getinfo尝试向这个地址写入8字节的响应码时,会越界覆盖栈上相邻的内存区域——恰好chunk是和res相邻的局部变量,导致chunk.memory指针被破坏,变成无效地址。

修复方案

  1. 核心修复:单独声明long类型变量存储响应码,避免复用CURLcode变量:
if ((res = curl_easy_perform(curl)) != CURLE_OK ) {
    printf("curl failed: %s\n", curl_easy_strerror(res));
} else {
    long response_code;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
    curl_easy_cleanup(curl);
    if (response != NULL) {
        *response = strdup(chunk.memory);
    }
}
  1. 额外优化建议:
    • WriteData中memset整个新分配内存的操作多余,只需在最后给字符串末尾加\0即可,减少不必要的内存操作;
    • curl_global_init应放在程序启动时调用一次,而非每次调用callApi都执行,避免重复初始化开销;
    • 完善错误处理逻辑:比如malloc/realloc失败时,要及时清理已分配的资源,避免内存泄漏;
    • callApi的返回值应返回实际的错误码或HTTP响应码,而非固定返回0,方便调用方判断结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 08:25:53