jsoncpp v0.5中的一个bug

本文目的

今天在使用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

但是,实际上却是:

clip_image002

抛异常了 囧~~~

 

原因分析

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]

posted @ 2011-12-28 12:32  bourneli  阅读(5861)  评论(1编辑  收藏  举报