C++请求币安API报错Run-time check failure #2 root变量栈损坏
报错原因
该报错是Windows平台VS编译器开启运行时栈检查(/RTCs)时触发的典型内存错误,提示栈上root变量周边的内存被非法写入,你的代码存在3个直接触发问题的逻辑错误:
- 跨类型调用JsonCpp接口触发未定义行为:币安
/api/v3/time接口返回的serverTime字段为64位整数类型(示例返回:{"serverTime":1719876543210}),你调用root.get("serverTime","")时传入的默认值为字符串字面量,后续直接对返回的整型Json::Value对象调用asString(),跨类型强转会导致JsonCpp内部内存操作越界,直接破坏栈上root周边的内存。 - Json解析接口使用不符合约定:你调用
reader.parse(readBuffer.c_str(), root)时传入const char*类型指针,会匹配到JsonCpp旧版本中「就地修改输入缓冲区」的parse重载,该版本接口要求传入可写的字符缓冲区,c_str()返回的只读指针不符合接口要求,容易引发越界写入。 - 缺少请求有效性校验:你没有校验
curl_easy_perform的返回值,也没有校验HTTP响应状态码,如果请求失败(网络不通、证书错误、接口限流等),readBuffer中存储的不是合法JSON,后续解析逻辑会触发不可预期的内存错误。
另外代码存在一个易引发逻辑问题的不规范写法:main函数开头已经定义了CURLcode res变量,在curl执行块内又重复定义同名res变量造成变量遮蔽,容易导致后续逻辑判断出错。
修复方案
按以下步骤修改代码即可解决问题:
- 调整Json解析调用方式,直接传入
std::string类型的响应内容作为parse输入,避免使用要求可写缓冲区的重载接口 - 读取
serverTime字段时先校验字段存在性、类型匹配性,按64位整数类型读取值后再转为字符串输出,禁止对非字符串类型的Json::Value直接调用asString() - 增加curl请求返回值、HTTP状态码校验逻辑,所有错误分支都要正确清理curl资源,避免资源泄漏
- 移除重复定义的
res变量,补充curl全局初始化/清理逻辑 - 如果修改完代码仍报相同栈错误,重新编译你使用的JsonCpp源码,确保项目引用的头文件、链接的库为同版本编译产物,且项目的C/C++运行时库配置(MT/MTd/MD/MDd)和JsonCpp编译时的配置完全一致,避免因对象内存布局不匹配引发越界。
修复后的完整可运行代码:
#include <iostream> #include <curl/curl.h> #include "json/json.h" #include <string> size_t WriteCallback(char* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append(contents, size * nmemb); return size * nmemb; } int main() { CURL* curl; CURLcode res; std::string readBuffer; Json::Value root; Json::Reader reader; long http_code = 0; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://api.binance.com/api/v3/time"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); res = curl_easy_perform(curl); // 校验curl请求执行结果 if (res != CURLE_OK) { std::cout << "curl request failed: " << curl_easy_strerror(res) << std::endl; curl_easy_cleanup(curl); curl_global_cleanup(); return 1; } // 校验HTTP响应状态码 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); if (http_code != 200) { std::cout << "http request error, code: " << http_code << ", response: " << readBuffer << std::endl; curl_easy_cleanup(curl); curl_global_cleanup(); return 1; } // 传入string对象调用parse接口 bool parsingSuccessful = reader.parse(readBuffer, root); if (!parsingSuccessful) { std::cout << "Failed to parse response: " << reader.getFormattedErrorMessages() << std::endl; curl_easy_cleanup(curl); curl_global_cleanup(); return 1; } // 按64位整数类型读取时间戳,转字符串输出 if (root.isMember("serverTime") && root["serverTime"].isInt64()) { std::cout << std::to_string(root["serverTime"].asInt64()) << std::endl; } else { std::cout << "serverTime field missing or type mismatch" << std::endl; } curl_easy_cleanup(curl); } curl_global_cleanup(); return 0; }
内容的提问来源于stack exchange,提问作者Remì1998
相关产品推荐
相关产品推荐

