本文目的
今天在使用jsoncpp 0.5的時候很偶然的發現了一個bug,由於jsoncpp在業界被廣泛使用,所以有必要將這個bug指出。
一個例子
/*
* bug_demo.cpp
*
* Created on: 2011-11-22
* Author: bourneli
*/
#include "json/json.h"
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
Json::Value oRootVal;
Json::Reader oJsonReader;
oJsonReader.parse("{\"aInt\" : 3}", oRootVal);
Json::Value oInt = oRootVal["aInt"];
cout << "aInt : " << oInt.asInt() << endl;
if (oInt.isConvertibleTo(Json::stringValue))
{
cout << "aInt as string : " << oInt.asString() << endl;
}
else
{
cout << "aInt cannot convert to a string" << endl;
}
return 0;
}
根據上面的代碼,如果使用過jsoncpp,應該可以預測輸出,如下:
| aInt : 3 aInt as string : 3 |
但是,實際上卻是:
拋異常了 囧~~~
原因分析
Json::Value::isConvertibleTo函數,從字面意思上看,就是判斷當前value是否可以轉成目標類型,我們看看Json::Value::isConvertibleTo的源代碼:
bool
Value::isConvertibleTo( ValueType other ) const
{
switch ( type_ )
{
case nullValue:
return true;
case intValue:
return ( other == nullValue && value_.int_ == 0 )
|| other == intValue
|| ( other == uintValue && value_.int_ >= 0 )
|| other == realValue
|| other == stringValue
|| other == booleanValue;
case uintValue:
return ( other == nullValue && value_.uint_ == 0 )
|| ( other == intValue && value_.uint_ <= (unsigned)maxInt )
|| other == uintValue
|| other == realValue
|| other == stringValue
|| other == booleanValue;
case realValue:
return ( other == nullValue && value_.real_ == 0.0 )
|| ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt )
|| ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt )
|| other == realValue
|| other == stringValue
|| other == booleanValue;
case booleanValue:
return ( other == nullValue && value_.bool_ == false )
|| other == intValue
|| other == uintValue
|| other == realValue
|| other == stringValue
|| other == booleanValue;
case stringValue:
return other == stringValue
|| ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) );
case arrayValue:
return other == arrayValue
|| ( other == nullValue && value_.map_->size() == 0 );
case objectValue:
return other == objectValue
|| ( other == nullValue && value_.map_->size() == 0 );
default:
JSON_ASSERT_UNREACHABLE;
}
return false; // unreachable;
}
實現很簡單,就是一系列的類型轉換映射。上面的代碼中第13行的地方就說明,int類型的Value是可以轉化成string類型的Value。
但是實際上,卻拋出了異常,我們可以分析下Json::Value::AsString函數的實現,源代碼如下:
std::string
Value::asString() const
{
switch ( type_ )
{
case nullValue:
return "";
case stringValue:
return value_.string_ ? value_.string_ : "";
case booleanValue:
return value_.bool_ ? "true" : "false";
case intValue:
case uintValue:
case realValue:
case arrayValue:
case objectValue:
JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" );
default:
JSON_ASSERT_UNREACHABLE;
}
return ""; // unreachable
}
實現也很簡單,也是通過當前value的類型,判斷是否可以轉成string類型。第12行和第17行表明:轉換映射和isConvertibleTo不一致。這就是導致bug的直接原因。
總結
此bug不是什么致命bug,並不能掩蓋jsoncpp的跨平台,簡單,輕量級等優點,使用的時候需要注意這里,否則會帶來問題。所以,建議不要使用isConvertibleTo這個函數,而是通過手動判斷當前數據類型,然后使用C++內置的類型轉換,就不會出現該問題。
相關資料
下面的鏈接是jsoncpp在sourceforge官方網站上對該bug的描述
https://sourceforge.net/tracker/index.php?func=detail&aid=3021877&group_id=144446&atid=758826
沒有注冊的同學無法瀏覽,這里截個圖:


![clip_image002[5] clip_image002[5]](/image/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vY25ibG9nc19jb20vYm91cm5lbGkvMjAxMTEyLzIwMTExMjI4MTIzOTEwNDUxMS5qcGc=.png)