本文目的
今天在使用jsoncpp 0.5的时候很偶然的发现了一个bug,由于jsoncpp在业界被广泛使用,所以有必要将这个bug指出。
一个例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/* * 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的源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
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函数的实现,源代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
没有注册的同学无法浏览,这里截个图: