URL编码函数get_encoded_string偶现重复返回旧值问题求助
问题分析:URL编码器偶现返回旧值的原因
问题背景
实现的URL编码器中,get_encoded_string函数偶发返回上一次调用的结果。例如调用call_api("api_key", "pokerName","message")时,该函数先后处理"pokerName"和"message",但有时会两次返回"pokerName"。
相关代码
call_api方法
char* call_api(const char* api_key, const char* pokerName, const char* message) { CURL* curl; CURLcode res; curl = curl_easy_init(); char errbuf[CURL_ERROR_SIZE]; /* string builder */ char url[MAX_MESSAGE_SIZE]; snprintf( url, sizeof(url), "%s%s%s%s%s%s", "http://xdroid.net/api/message?k=", api_key, "&t=", get_encoded_string(pokerName), "&c=", get_encoded_string(message)); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); struct curl_slist* headers = NULL; curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); const char* data = ""; curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); res = curl_easy_perform(curl); if (res == CURLE_OK) { return "success"; } else { return errbuf; } curl_easy_cleanup(curl); }
get_encoded_string函数
char* get_encoded_string(char* string_to_encode) { CURL* curl = curl_easy_init(); /* convert a string into a URL encoded string */ char* encoded_message = curl_easy_escape(curl, string_to_encode, 0); curl_free(encoded_message); curl_easy_cleanup(curl); return encoded_message; }
问题原因分析
- 核心错误:返回已释放的野指针
get_encoded_string中,curl_easy_escape会在堆上分配内存存储编码后的字符串,并将地址赋值给encoded_message。但函数紧接着调用curl_free(encoded_message)释放了这块内存,之后却返回这个已经失效的指针。此时指针指向的是已被释放的内存区域,属于典型的野指针。 - 偶现旧值的本质
被释放的内存不会立刻被系统回收或覆盖:当第二次调用get_encoded_string时,如果新分配的内存恰好和第一次释放的地址重合,就会覆盖旧值;但如果内存未被覆盖、或后续分配的内存地址不同,原内存区域残留的旧数据就会被返回,这就是问题偶发的根本原因。 - 额外风险提示
这种野指针行为还可能导致程序崩溃、内存损坏等更严重的问题,返回旧值只是其中一种表现。
修复建议
修改get_encoded_string,不要提前释放编码后的字符串,将其返回给调用者,由调用者在使用完成后负责释放:
char* get_encoded_string(char* string_to_encode) { CURL* curl = curl_easy_init(); if (!curl) { return NULL; // 处理curl初始化失败的情况 } char* encoded_message = curl_easy_escape(curl, string_to_encode, 0); curl_easy_cleanup(curl); return encoded_message; }
然后在call_api中,使用完编码字符串后手动释放内存:
char* encoded_pokerName = get_encoded_string(pokerName); char* encoded_message = get_encoded_string(message); snprintf( url, sizeof(url), "%s%s%s%s%s%s", "http://xdroid.net/api/message?k=", api_key, "&t=", encoded_pokerName, "&c=", encoded_message); // 使用完成后释放内存 curl_free(encoded_pokerName); curl_free(encoded_message);
内容的提问来源于stack exchange,提问作者CodeEnjoyer
相关产品推荐
相关产品推荐

