jsoncpp 是 C++ 常用 JSON 庫,但其錯誤處理機制依賴 assert,在 Linux 下觸發會調用 abort() 導致進程崩潰(收到 SIGABRT),對服務端極其危險。本文總結常見崩潰場景與規避方案。
現象:解析 "1111 {}" 這類非法 JSON,jsoncpp 不報錯而是將其視為字符串。隨後調用 value["key"] 或 value[index] 觸發 assert(type_ == nullValue || type_ == objectValue) 崩潰。
解決:啟用嚴格模式,非法 JSON 直接返回 false:
Json::Reader reader(Json::Features::strictMode());
if (!reader.parse(str, value)) { /* 處理錯誤 */ }
現象:JSON 中 "friends": [{"name":"A"},{"name":"B"}] 是數組。代碼 value["friends"]["name"] 嘗試用字符串鍵訪問數組,觸發同類 assert。
解決:先取數組對象,再遍歷索引訪問:
Json::Value friends = value["friends"];
for (int i = 0; i < friends.size(); ++i)
cout << friends[i]["name"].asString();
現象:JSON 值為字符串 "age":"24",代碼 value["age"].asInt() 強制轉整數,觸發 assert。
解決:先判斷類型再轉換:
if (value["age"].isInt()) int age = value["age"].asInt();
else if (value["age"].isString()) int age = stoi(value["age"].asString());
#include
#include
#include
using namespace std;
int main() {
Json::Reader reader(Json::Features::strictMode());
string str = "{\"name\":\"tom\",\"age\":\"24\",\"friends\":[{\"name\":\"A\"},{\"name\":\"B\"}]}";
Json::Value root;
if (!reader.parse(str, root)) { cerr << "parse error\n"; return -1; }
string name = root["name"].asString();
int age = 0;
if (root["age"].isInt()) age = root["age"].asInt();
else if (root["age"].isString()) age = stoi(root["age"].asString());
Json::Value friends = root["friends"];
for (int i = 0; i < friends.size(); ++i)
cout << friends[i]["name"].asString() << endl;
return 0;
}
#include
#include
#include
using namespace std;
int main() {
Json::Value root;
Json::FastWriter writer;
Json::Value person;
person["name"] = "hello world";
person["age"] = 100;
root.append(person);
string json_str = writer.write(root);
ofstream ofs("out.json");
assert(ofs.is_open());
ofs << json_str;
return 0;
}
因 jsoncpp 依賴 assert、非法輸入易崩潰,且 SDK 接入多為 PHP/Python 生態,建議:
nlohmann/json(異常機制而非 assert)或 rapidjson(無異常、高性能)。jsoncpp 功能完整但錯誤處理機制不適合高可用服務端。必須:
strictMode 拒絕非法 JSON。isArray()/isObject()/isInt() 等類型。