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
相关产品推荐
相关产品推荐

