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"
|
||||
#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
|
||||
#include <stdexcept>
|
||||
#define JSON_ASSERT(condition) \
|
||||
{if (!(condition)) {throw std::logic_error( "assert json failed" );}} // @todo <= add detail about condition in exception
|
||||
#define JSON_FAIL_MESSAGE(message) \
|
||||
|
||||
// @todo <= add detail about condition in exception
|
||||
# define JSON_ASSERT(condition) \
|
||||
{if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
|
||||
|
||||
# define JSON_FAIL_MESSAGE(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
|
||||
#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
|
||||
// release bugs we abort, for a core-dump or debugger.
|
||||
#define JSON_FAIL_MESSAGE(message) \
|
||||
// release builds we abort, for a core-dump or debugger.
|
||||
# define JSON_FAIL_MESSAGE(message) \
|
||||
{ \
|
||||
std::ostringstream oss; oss << message; \
|
||||
assert(false && oss.str().c_str()); \
|
||||
|
@ -11,6 +11,7 @@
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
#ifndef JSON_USE_CPPTL_SMALLMAP
|
||||
#include <map>
|
||||
@ -32,6 +33,23 @@
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
enum ValueType {
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
/** Write Value into document as configured in sub-class.
|
||||
Do not take ownership of sout, but maintain a reference during function.
|
||||
\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
|
||||
*/
|
||||
virtual int write(Value const& root, std::ostream* sout) = 0;
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||
#define snprintf _snprintf
|
||||
@ -148,7 +147,7 @@ bool Reader::readValue() {
|
||||
// But this deprecated class has a security problem: Bad input can
|
||||
// cause a seg-fault. This seems like a fair, binary-compatible way
|
||||
// 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;
|
||||
|
||||
Token token;
|
||||
@ -1107,7 +1106,7 @@ bool OurReader::parse(const char* beginDoc,
|
||||
}
|
||||
|
||||
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_;
|
||||
Token token;
|
||||
skipCommentTokens(token);
|
||||
@ -1431,7 +1430,7 @@ bool OurReader::readObject(Token& tokenStart) {
|
||||
return addErrorAndRecover(
|
||||
"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)) {
|
||||
std::string msg = "Duplicate key: '" + name + "'";
|
||||
return addErrorAndRecover(
|
||||
@ -1994,7 +1993,7 @@ std::istream& operator>>(std::istream& sin, Value& root) {
|
||||
"Error from reader: %s",
|
||||
errs.c_str());
|
||||
|
||||
JSON_FAIL_MESSAGE("reader error");
|
||||
throwRuntimeError("reader error");
|
||||
}
|
||||
return sin;
|
||||
}
|
||||
|
@ -87,9 +87,11 @@ static inline char* duplicateStringValue(const char* value,
|
||||
length = Value::maxInt - 1;
|
||||
|
||||
char* newString = static_cast<char*>(malloc(length + 1));
|
||||
JSON_ASSERT_MESSAGE(newString != 0,
|
||||
"in Json::Value::duplicateStringValue(): "
|
||||
"Failed to allocate string value buffer");
|
||||
if (newString == NULL) {
|
||||
throwRuntimeError(
|
||||
"in Json::Value::duplicateStringValue(): "
|
||||
"Failed to allocate string value buffer");
|
||||
}
|
||||
memcpy(newString, value, length);
|
||||
newString[length] = 0;
|
||||
return newString;
|
||||
@ -108,9 +110,11 @@ static inline char* duplicateAndPrefixStringValue(
|
||||
"length too big for prefixing");
|
||||
unsigned actualLength = length + sizeof(unsigned) + 1U;
|
||||
char* newString = static_cast<char*>(malloc(actualLength));
|
||||
JSON_ASSERT_MESSAGE(newString != 0,
|
||||
"in Json::Value::duplicateAndPrefixStringValue(): "
|
||||
"Failed to allocate string value buffer");
|
||||
if (newString == 0) {
|
||||
throwRuntimeError(
|
||||
"in Json::Value::duplicateAndPrefixStringValue(): "
|
||||
"Failed to allocate string value buffer");
|
||||
}
|
||||
*reinterpret_cast<unsigned*>(newString) = length;
|
||||
memcpy(newString + sizeof(unsigned), value, length);
|
||||
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 {
|
||||
|
||||
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 <utility>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
@ -1080,7 +1079,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
||||
} else if (cs_str == "None") {
|
||||
cs = CommentStyle::None;
|
||||
} else {
|
||||
throw std::runtime_error("commentStyle must be 'All' or 'None'");
|
||||
throwRuntimeError("commentStyle must be 'All' or 'None'");
|
||||
}
|
||||
std::string colonSymbol = " : ";
|
||||
if (eyc) {
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "jsontest.h"
|
||||
#include <json/config.h>
|
||||
#include <json/json.h>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
|
||||
// Make numeric limits more convenient to talk about.
|
||||
|
Loading…
x
Reference in New Issue
Block a user