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]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM