C++使用cURL实现Valorant登录时Release模式报Invalid Parameter错误
问题描述
我正在开发一款使用cURL实现Valorant账号登录的C++程序,代码在Visual Studio 2019 Debug模式下运行正常,但切换到Release模式时抛出Invalid Parameter错误。经调研初步判断问题与libcurl相关,但未找到公开解决方案。项目同时使用了nlohmann/json库和base64解码代码片段,经排查二者与该错误无关。项目采用默认配置,我也曾新建项目迁移全部代码,问题仍可复现。
完整代码
#include <iostream> #include "json.hpp" #include <curl/curl.h> #include <string> #include <sstream> #include "base64.hpp" #include <stdio.h> using json = nlohmann::json; CURL* hnd = curl_easy_init(); size_t WriteCallback(char* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } void authCookies() { curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(hnd, CURLOPT_URL, "https://auth.riotgames.com/api/v1/authorization"); struct curl_slist* headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\"client_id\":\"play-valorant-web-prod\",\"nonce\":\"1\",\"redirect_uri\":\"https://playvalorant.com/opt_in\",\"response_type\":\"token id_token\"}"); CURLcode ret = curl_easy_perform(hnd); } std::string getAuthToken(std::string username, std::string password) { std::string token = ""; curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "PUT"); curl_easy_setopt(hnd, CURLOPT_URL, "https://auth.riotgames.com/api/v1/authorization"); struct curl_slist* headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); std::string response; json toSend = { {"type", "auth"}, {"username", username}, {"password", password}, {"remember", false}, {"language", "en_US"} }; std::string sendText = toSend.dump(4); curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, sendText.c_str()); curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &response); CURLcode ret = curl_easy_perform(hnd); json resp = json::parse(response); //parse the uri and look for a token std::string uri = std::string(resp["response"]["parameters"]["uri"]); size_t loc = uri.find("#access_token="); for (int i = loc + 14; i < uri.length(); i++) { if (uri[i] != '&') { token += uri[i]; } else { break; } } return token; } void cookieReauth() { std::string response; curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET"); curl_easy_setopt(hnd, CURLOPT_URL, "https://auth.riotgames.com/authorize?redirect_uri=https%3A%2F%2Fplayvalorant.com%2Fopt_in&client_id=play-valorant-web-prod&response_type=token%20id_token"); curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, ""); curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &response); CURLcode ret = curl_easy_perform(hnd); } std::string getEntitlement(std::string token) { std::string out = ""; curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(hnd, CURLOPT_URL, "https://entitlements.auth.riotgames.com/api/token/v1"); struct curl_slist* headers = NULL; std::string auth = "Authorization: Bearer " + token; headers = curl_slist_append(headers, auth.c_str()); headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, ""); curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &out); curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); CURLcode ret = curl_easy_perform(hnd); json resp = json::parse(out); return std::string(resp["entitlements_token"]); } struct valorantUser { std::string displayName; std::string puuid; std::string name; std::string tag; }; std::vector<valorantUser> getUsersByPuuid(std::string token, std::string entitlement, json puuidList, std::string region) { std::vector<valorantUser> userList; std::string response; curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "PUT"); curl_easy_setopt(hnd, CURLOPT_URL, std::string("https://pd." + region + ".a.pvp.net/name-service/v2/players").c_str()); struct curl_slist* headers = NULL; std::string auth = "Authorization: Bearer " + token; std::string ent = "Entitlements: " + entitlement; headers = curl_slist_append(headers, auth.c_str()); headers = curl_slist_append(headers, ent.c_str()); headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); std::string toSend = puuidList.dump(); curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, toSend.c_str()); curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &response); CURLcode ret = curl_easy_perform(hnd); json resData = json::parse(response); for (int i = 0; i < resData.size(); i++) { valorantUser dat; dat.displayName = std::string(resData[i]["DisplayName"]); dat.puuid = std::string(resData[i]["Subject"]); dat.name = std::string(resData[i]["GameName"]); dat.tag = std::string(resData[i]["TagLine"]); userList.push_back(dat); } return userList; } std::string getTokenPuuid(std::string token) { std::vector<std::string> toks; std::stringstream test(token); std::string cur; while (std::getline(test, cur, '.')) { toks.push_back(cur); } json decoded = json::parse(base64_decode(toks[1])); return decoded["sub"]; } int main() { curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(hnd, CURLOPT_COOKIEJAR, ""); authCookies(); //get auth cookies std::string token = getAuthToken("username", "password"); //get auth token cookieReauth(); //get more auth cookies std::string entitlement = getEntitlement(token); //get entitlement token std::string puuid = getTokenPuuid(token); //get user puuid from token json puuidList = json::array({puuid}); valorantUser botData = getUsersByPuuid(token, entitlement, puuidList, "na")[0]; //get user name from puuid std::cout << "Signed in as " << botData.name << "#" << botData.tag; }
错误截图


补充测试信息
注释掉所有业务函数后错误消失,仅取消authCookies()函数的注释错误就会复现,且异常直到代码执行到末尾时才会触发。测试用main函数代码如下:
int main() { curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(hnd, CURLOPT_COOKIEJAR, ""); /* authCookies(); //get auth cookies std::string token = getAuthToken("username", "password"); //get auth token cookieReauth(); //get more auth cookies std::string entitlement = getEntitlement(token); //get entitlement token std::string puuid = getTokenPuuid(token); //get user puuid from token json puuidList = json::array({ puuid }); valorantUser botData = getUsersByPuuid(token, entitlement, puuidList, "na")[0]; //get user name from puuid std::cout << "Signed in as " << botData.name << "#" << botData.tag;*/ curl_easy_cleanup(hnd); return 0; }
修复方案
问题根因
- 缺少libcurl全局环境初始化:未调用
curl_global_init(),全局CURL句柄初始化时curl环境还未就绪,Release模式下时序检查更严格直接触发错误。 authCookies函数中未设置CURLOPT_WRITEDATA,导致WriteCallback回调收到的userp为空指针,调用std::string::append触发非法参数错误。- 请求头
curl_slist使用后未释放,存在内存泄漏隐患。
修复步骤
- 移除全局CURL句柄的初始化,改为main函数内先初始化curl全局环境再创建句柄:
// 移除原来的全局CURL* hnd = curl_easy_init(); 改为全局声明,main内初始化 CURL* hnd = nullptr; int main() { // 第一步先初始化curl全局环境 curl_global_init(CURL_GLOBAL_ALL); hnd = curl_easy_init(); if (!hnd) { std::cerr << "curl初始化失败" << std::endl; return 1; } curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(hnd, CURLOPT_COOKIEJAR, ""); authCookies(); std::string token = getAuthToken("username", "password"); cookieReauth(); std::string entitlement = getEntitlement(token); std::string puuid = getTokenPuuid(token); json puuidList = json::array({puuid}); valorantUser botData = getUsersByPuuid(token, entitlement, puuidList, "na")[0]; std::cout << "Signed in as " << botData.name << "#" << botData.tag; // 程序结束前清理 curl_easy_cleanup(hnd); curl_global_cleanup(); return 0; }
- 给
authCookies函数添加CURLOPT_WRITEDATA配置,同时释放请求头内存:
void authCookies() { std::string dummy_resp; curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(hnd, CURLOPT_URL, "https://auth.riotgames.com/api/v1/authorization"); struct curl_slist* headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\"client_id\":\"play-valorant-web-prod\",\"nonce\":\"1\",\"redirect_uri\":\"https://playvalorant.com/opt_in\",\"response_type\":\"token id_token\"}"); curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &dummy_resp); CURLcode ret = curl_easy_perform(hnd); curl_slist_free_all(headers); }
- 所有使用
curl_slist_append创建的请求头,在curl_easy_perform执行完成后都调用curl_slist_free_all释放内存。 - 可选优化:不要用
CURLOPT_CUSTOMREQUEST设置请求方法,POST请求用CURLOPT_POST、PUT请求用CURLOPT_PUT替代,避免潜在的方法识别错误。
按以上步骤修改后,Release模式的Invalid Parameter错误即可解决。
内容的提问来源于stack exchange,提问作者user14628419
相关产品推荐
相关产品推荐

