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

C代码仅在GDB调试时运行正常,直接执行失败的问题排查

问题:程序仅在GDB调试时正常运行,直接执行失败

我的代码通过GDB调试(执行gdb ./MyCode后输入run命令)时能正常工作,但直接运行./MyCode就会失败。问题出在packageBuildFileDownload函数,该函数因cJSON_PrintPreallocated调用失败返回false,且该现象仅在非GDB调试场景下出现。

问题代码片段

bool packageBuildFileDownload(char* receiver, char* finished, char* file_name, char* payload, char** json_string, size_t json_string_size) {
    cJSON* json = packageCreateJson();
    if (!json) return false;
        
    typedef struct PackageAttribute {
        char
            *name, 
            *value;
    } PackageAttribute;
    
    PackageAttribute attributes[] = {
        {
            .name = "type", 
            .value = "filedownload"
        }, 
        {
            .name = "receiver", 
            .value = receiver
        }, 
        {
            .name = "file_name", 
            .value = file_name
        }, 
        {
            .name = "finished", 
            .value = finished
        }, 
        {
            .name = "payload", 
            .value = payload
        }           
    };
    int attributes_size = sizeof(attributes) / sizeof(attributes[0]);
    
    for (int i = 0; i < attributes_size; i++) {
        if (!cJSON_AddStringToObject(json, attributes[i].name, attributes[i].value)) {
            cJSON_Delete(json);
            return false;
        }
    }

    if (!cJSON_PrintPreallocated(json, *json_string, json_string_size, false)) {
        // cJSON_PrintPreallocated 返回失败
        cJSON_Delete(json);
        return false;
    }
    
    cJSON_Delete(json);
    return true;
}

static bool filedownloadrequestSendResponse(Socket* socket, uint8_t* file_buffer, size_t file_buffer_size, char* receiver, char* finished, char* file_name) {
    char* b64_encode_buffer;
    base64Encode(file_buffer, file_buffer_size, &b64_encode_buffer);

    char* json_string = malloc(RESPONSE_PACKAGE_BUFFER_SIZE);
    if (!packageBuildFileDownload(receiver, finished, file_name, b64_encode_buffer, &json_string, strlen(json_string))) {
        free(json_string);
        return false;
    }
    
    free(b64_encode_buffer);
    
    CURLcode result = sendWs(socket->curl, json_string);
    free(json_string);
    if (result != CURLE_OK) {
        fprintf(stderr, "sendWs() failed: %s\n", curl_easy_strerror(result));
        return false;
    }
    
    return true;
}

问题根源

核心错误在filedownloadrequestSendResponse函数的调用参数上:

if (!packageBuildFileDownload(..., strlen(json_string))) {

json_string是刚通过malloc分配的内存,未初始化,内存中是随机垃圾数据。调用strlen(json_string)属于未定义行为:

  • 在GDB调试环境中,调试堆通常会将分配的内存初始化为固定值(比如0x00或0xcd),如果恰好遇到早期的\0,strlen返回的数值可能刚好满足cJSON_PrintPreallocated的需求;
  • 在非调试环境中,malloc的内存是随机的,strlen会读到一个远小于实际分配的RESPONSE_PACKAGE_BUFFER_SIZE的值,导致cJSON_PrintPreallocated因缓冲区空间不足而失败。

修复方案

将调用packageBuildFileDownload时的最后一个参数从strlen(json_string)替换为实际分配的缓冲区大小RESPONSE_PACKAGE_BUFFER_SIZE:

char* json_string = malloc(RESPONSE_PACKAGE_BUFFER_SIZE);
if (!packageBuildFileDownload(receiver, finished, file_name, b64_encode_buffer, &json_string, RESPONSE_PACKAGE_BUFFER_SIZE)) {
    free(json_string);
    return false;
}

额外优化建议

如果想避免缓冲区大小不足的问题,可以先预计算JSON字符串的长度,再分配对应大小的内存:

// 在packageBuildFileDownload函数中,替换cJSON_PrintPreallocated的逻辑
char* temp_json = cJSON_PrintUnformatted(json);
if (!temp_json) {
    cJSON_Delete(json);
    return false;
}
size_t required_size = strlen(temp_json) + 1; // 包含末尾的\0
if (required_size > json_string_size) {
    free(temp_json);
    cJSON_Delete(json);
    return false;
}
strcpy(*json_string, temp_json);
free(temp_json);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 12:00:54