mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-01-31 14:39:52 +01:00
Merge pull request #211 from cdunn2001/except
* Add Json::Exception and derivatives. * Clarify when exceptions are thrown, to avoid crashes caused by malicious input. * Use our own type (derived fro std::exception) so they are trappable.
This commit is contained in:
commit
0d33cb3639
@ -13,22 +13,30 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
|
/** It should not be possible for a maliciously designed file to
|
||||||
|
* cause an abort() or seg-fault, so these macros are used only
|
||||||
|
* for pre-condition violations and internal logic errors.
|
||||||
|
*/
|
||||||
#if JSON_USE_EXCEPTION
|
#if JSON_USE_EXCEPTION
|
||||||
#include <stdexcept>
|
|
||||||
#define JSON_ASSERT(condition) \
|
// @todo <= add detail about condition in exception
|
||||||
{if (!(condition)) {throw std::logic_error( "assert json failed" );}} // @todo <= add detail about condition in exception
|
# define JSON_ASSERT(condition) \
|
||||||
#define JSON_FAIL_MESSAGE(message) \
|
{if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
|
||||||
|
|
||||||
|
# define JSON_FAIL_MESSAGE(message) \
|
||||||
{ \
|
{ \
|
||||||
std::ostringstream oss; oss << message; \
|
std::ostringstream oss; oss << message; \
|
||||||
throw std::logic_error(oss.str()); \
|
Json::throwLogicError(oss.str()); \
|
||||||
|
abort(); \
|
||||||
}
|
}
|
||||||
//#define JSON_FAIL_MESSAGE(message) throw std::logic_error(message)
|
|
||||||
#else // JSON_USE_EXCEPTION
|
#else // JSON_USE_EXCEPTION
|
||||||
#define JSON_ASSERT(condition) assert(condition)
|
|
||||||
|
# define JSON_ASSERT(condition) assert(condition)
|
||||||
|
|
||||||
// The call to assert() will show the failure message in debug builds. In
|
// The call to assert() will show the failure message in debug builds. In
|
||||||
// release bugs we abort, for a core-dump or debugger.
|
// release builds we abort, for a core-dump or debugger.
|
||||||
#define JSON_FAIL_MESSAGE(message) \
|
# define JSON_FAIL_MESSAGE(message) \
|
||||||
{ \
|
{ \
|
||||||
std::ostringstream oss; oss << message; \
|
std::ostringstream oss; oss << message; \
|
||||||
assert(false && oss.str().c_str()); \
|
assert(false && oss.str().c_str()); \
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
#ifndef JSON_USE_CPPTL_SMALLMAP
|
#ifndef JSON_USE_CPPTL_SMALLMAP
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -32,6 +33,23 @@
|
|||||||
*/
|
*/
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
|
/** Base class for all exceptions we throw.
|
||||||
|
*/
|
||||||
|
class JSON_API Exception;
|
||||||
|
/** Exceptions which the user cannot easily avoid.
|
||||||
|
*
|
||||||
|
* E.g. out-of-memory, stack-overflow, malicious input
|
||||||
|
*/
|
||||||
|
class JSON_API RuntimeError;
|
||||||
|
/** Exceptions throw by JSON_ASSERT/JSON_FAIL macros.
|
||||||
|
*
|
||||||
|
* These are precondition-violations (user bugs) and internal errors (our bugs).
|
||||||
|
*/
|
||||||
|
class JSON_API LogicError;
|
||||||
|
|
||||||
|
JSON_API void throwRuntimeError(std::string const& msg);
|
||||||
|
JSON_API void throwLogicError(std::string const& msg);
|
||||||
|
|
||||||
/** \brief Type of the value held by a Value object.
|
/** \brief Type of the value held by a Value object.
|
||||||
*/
|
*/
|
||||||
enum ValueType {
|
enum ValueType {
|
||||||
|
@ -46,7 +46,7 @@ public:
|
|||||||
/** Write Value into document as configured in sub-class.
|
/** Write Value into document as configured in sub-class.
|
||||||
Do not take ownership of sout, but maintain a reference during function.
|
Do not take ownership of sout, but maintain a reference during function.
|
||||||
\pre sout != NULL
|
\pre sout != NULL
|
||||||
\return zero on success
|
\return zero on success (For now, we always return zero, so check the stream instead.)
|
||||||
\throw std::exception possibly, depending on configuration
|
\throw std::exception possibly, depending on configuration
|
||||||
*/
|
*/
|
||||||
virtual int write(Value const& root, std::ostream* sout) = 0;
|
virtual int write(Value const& root, std::ostream* sout) = 0;
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@ -148,7 +147,7 @@ bool Reader::readValue() {
|
|||||||
// But this deprecated class has a security problem: Bad input can
|
// But this deprecated class has a security problem: Bad input can
|
||||||
// cause a seg-fault. This seems like a fair, binary-compatible way
|
// cause a seg-fault. This seems like a fair, binary-compatible way
|
||||||
// to prevent the problem.
|
// to prevent the problem.
|
||||||
if (stackDepth_g >= stackLimit_g) throw std::runtime_error("Exceeded stackLimit in readValue().");
|
if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
|
||||||
++stackDepth_g;
|
++stackDepth_g;
|
||||||
|
|
||||||
Token token;
|
Token token;
|
||||||
@ -1107,7 +1106,7 @@ bool OurReader::parse(const char* beginDoc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool OurReader::readValue() {
|
bool OurReader::readValue() {
|
||||||
if (stackDepth_ >= features_.stackLimit_) throw std::runtime_error("Exceeded stackLimit in readValue().");
|
if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
|
||||||
++stackDepth_;
|
++stackDepth_;
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens(token);
|
skipCommentTokens(token);
|
||||||
@ -1431,7 +1430,7 @@ bool OurReader::readObject(Token& tokenStart) {
|
|||||||
return addErrorAndRecover(
|
return addErrorAndRecover(
|
||||||
"Missing ':' after object member name", colon, tokenObjectEnd);
|
"Missing ':' after object member name", colon, tokenObjectEnd);
|
||||||
}
|
}
|
||||||
if (name.length() >= (1U<<30)) throw std::runtime_error("keylength >= 2^30");
|
if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
|
||||||
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
|
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
|
||||||
std::string msg = "Duplicate key: '" + name + "'";
|
std::string msg = "Duplicate key: '" + name + "'";
|
||||||
return addErrorAndRecover(
|
return addErrorAndRecover(
|
||||||
@ -1994,7 +1993,7 @@ std::istream& operator>>(std::istream& sin, Value& root) {
|
|||||||
"Error from reader: %s",
|
"Error from reader: %s",
|
||||||
errs.c_str());
|
errs.c_str());
|
||||||
|
|
||||||
JSON_FAIL_MESSAGE("reader error");
|
throwRuntimeError("reader error");
|
||||||
}
|
}
|
||||||
return sin;
|
return sin;
|
||||||
}
|
}
|
||||||
|
@ -87,9 +87,11 @@ static inline char* duplicateStringValue(const char* value,
|
|||||||
length = Value::maxInt - 1;
|
length = Value::maxInt - 1;
|
||||||
|
|
||||||
char* newString = static_cast<char*>(malloc(length + 1));
|
char* newString = static_cast<char*>(malloc(length + 1));
|
||||||
JSON_ASSERT_MESSAGE(newString != 0,
|
if (newString == NULL) {
|
||||||
"in Json::Value::duplicateStringValue(): "
|
throwRuntimeError(
|
||||||
"Failed to allocate string value buffer");
|
"in Json::Value::duplicateStringValue(): "
|
||||||
|
"Failed to allocate string value buffer");
|
||||||
|
}
|
||||||
memcpy(newString, value, length);
|
memcpy(newString, value, length);
|
||||||
newString[length] = 0;
|
newString[length] = 0;
|
||||||
return newString;
|
return newString;
|
||||||
@ -108,9 +110,11 @@ static inline char* duplicateAndPrefixStringValue(
|
|||||||
"length too big for prefixing");
|
"length too big for prefixing");
|
||||||
unsigned actualLength = length + sizeof(unsigned) + 1U;
|
unsigned actualLength = length + sizeof(unsigned) + 1U;
|
||||||
char* newString = static_cast<char*>(malloc(actualLength));
|
char* newString = static_cast<char*>(malloc(actualLength));
|
||||||
JSON_ASSERT_MESSAGE(newString != 0,
|
if (newString == 0) {
|
||||||
"in Json::Value::duplicateAndPrefixStringValue(): "
|
throwRuntimeError(
|
||||||
"Failed to allocate string value buffer");
|
"in Json::Value::duplicateAndPrefixStringValue(): "
|
||||||
|
"Failed to allocate string value buffer");
|
||||||
|
}
|
||||||
*reinterpret_cast<unsigned*>(newString) = length;
|
*reinterpret_cast<unsigned*>(newString) = length;
|
||||||
memcpy(newString + sizeof(unsigned), value, length);
|
memcpy(newString + sizeof(unsigned), value, length);
|
||||||
newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
|
newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
|
||||||
@ -148,6 +152,47 @@ static inline void releaseStringValue(char* value) { free(value); }
|
|||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
|
class JSON_API Exception : public std::exception {
|
||||||
|
public:
|
||||||
|
Exception(std::string const& msg);
|
||||||
|
virtual ~Exception() throw();
|
||||||
|
virtual char const* what() const throw();
|
||||||
|
protected:
|
||||||
|
std::string const& msg_;
|
||||||
|
};
|
||||||
|
class JSON_API RuntimeError : public Exception {
|
||||||
|
public:
|
||||||
|
RuntimeError(std::string const& msg);
|
||||||
|
};
|
||||||
|
class JSON_API LogicError : public Exception {
|
||||||
|
public:
|
||||||
|
LogicError(std::string const& msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
Exception::Exception(std::string const& msg)
|
||||||
|
: msg_(msg)
|
||||||
|
{}
|
||||||
|
Exception::~Exception() throw()
|
||||||
|
{}
|
||||||
|
char const* Exception::what() const throw()
|
||||||
|
{
|
||||||
|
return msg_.c_str();
|
||||||
|
}
|
||||||
|
RuntimeError::RuntimeError(std::string const& msg)
|
||||||
|
: Exception(msg)
|
||||||
|
{}
|
||||||
|
LogicError::LogicError(std::string const& msg)
|
||||||
|
: Exception(msg)
|
||||||
|
{}
|
||||||
|
void throwRuntimeError(std::string const& msg)
|
||||||
|
{
|
||||||
|
throw RuntimeError(msg);
|
||||||
|
}
|
||||||
|
void throwLogicError(std::string const& msg)
|
||||||
|
{
|
||||||
|
throw LogicError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -1080,7 +1079,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
|||||||
} else if (cs_str == "None") {
|
} else if (cs_str == "None") {
|
||||||
cs = CommentStyle::None;
|
cs = CommentStyle::None;
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("commentStyle must be 'All' or 'None'");
|
throwRuntimeError("commentStyle must be 'All' or 'None'");
|
||||||
}
|
}
|
||||||
std::string colonSymbol = " : ";
|
std::string colonSymbol = " : ";
|
||||||
if (eyc) {
|
if (eyc) {
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "jsontest.h"
|
#include "jsontest.h"
|
||||||
#include <json/config.h>
|
#include <json/config.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <stdexcept>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
// Make numeric limits more convenient to talk about.
|
// Make numeric limits more convenient to talk about.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user