Handler specifies structure and string limits

This commit is contained in:
Krystian Stasiowski 2020-09-07 13:44:58 -04:00 committed by Vinnie Falco
parent da65b25f4d
commit f3d0710e37
22 changed files with 478 additions and 372 deletions

View File

@ -387,6 +387,11 @@ class boost_null_impl : public any_impl
{ {
struct handler struct handler
{ {
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
bool on_document_begin(error_code&) { return true; } bool on_document_begin(error_code&) { return true; }
bool on_document_end(error_code&) { return true; } bool on_document_end(error_code&) { return true; }
bool on_object_begin(error_code&) { return true; } bool on_object_begin(error_code&) { return true; }

View File

@ -26,15 +26,16 @@ using namespace boost::json;
//[example_validate //[example_validate
bool // The null parser discards all the data
validate( string_view s ) class null_parser
{ {
// The null parser discards all the data
class null_parser
{
struct handler struct handler
{ {
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
bool on_document_begin( error_code& ) { return true; } bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; } bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; } bool on_object_begin( error_code& ) { return true; }
@ -57,7 +58,7 @@ validate( string_view s )
basic_parser<handler> p_; basic_parser<handler> p_;
public: public:
null_parser() null_parser()
: p_(parse_options()) : p_(parse_options())
{ {
@ -78,8 +79,11 @@ validate( string_view s )
ec = error::extra_data; ec = error::extra_data;
return n; return n;
} }
}; };
bool
validate( string_view s )
{
// Parse with the null parser and return false on error // Parse with the null parser and return false on error
null_parser p; null_parser p;
error_code ec; error_code ec;

View File

@ -17,13 +17,15 @@
using namespace boost::json; using namespace boost::json;
bool class null_parser
validate( string_view s )
{ {
class null_parser
{
struct handler struct handler
{ {
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
bool on_document_begin( error_code& ) { return true; } bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; } bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; } bool on_object_begin( error_code& ) { return true; }
@ -46,7 +48,7 @@ validate( string_view s )
basic_parser<handler> p_; basic_parser<handler> p_;
public: public:
null_parser() null_parser()
: p_(parse_options()) : p_(parse_options())
{ {
@ -67,8 +69,11 @@ validate( string_view s )
ec = error::extra_data; ec = error::extra_data;
return n; return n;
} }
}; };
bool
validate( string_view s )
{
// Parse with the null parser and return false on error // Parse with the null parser and return false on error
null_parser p; null_parser p;
error_code ec; error_code ec;

View File

@ -1022,7 +1022,7 @@ public:
std::size_t std::size_t
max_size() noexcept max_size() noexcept
{ {
return BOOST_JSON_MAX_STRUCTURED_SIZE; return array_impl::max_size();
} }
/** Return the number of elements that can be held in currently allocated memory. /** Return the number of elements that can be held in currently allocated memory.

View File

@ -965,10 +965,22 @@ parse_unescaped(const char* p)
cs = detail::count_valid<AllowBadUTF8>( cs = detail::count_valid<AllowBadUTF8>(
cs.begin(), cs.end()); cs.begin(), cs.end());
std::size_t size = cs.used(start); std::size_t size = cs.used(start);
if(IsKey)
{
BOOST_ASSERT(total <= Handler::max_key_size);
if(BOOST_JSON_UNLIKELY(size > if(BOOST_JSON_UNLIKELY(size >
BOOST_JSON_MAX_STRING_SIZE - total)) Handler::max_key_size - total))
return fail(cs.begin(), IsKey ? return fail(cs.begin(),
error::key_too_large : error::string_too_large); error::key_too_large);
}
else
{
BOOST_ASSERT(total <= Handler::max_string_size);
if(BOOST_JSON_UNLIKELY(size >
Handler::max_string_size - total))
return fail(cs.begin(),
error::string_too_large);
}
total += size; total += size;
if(BOOST_JSON_UNLIKELY(! cs)) if(BOOST_JSON_UNLIKELY(! cs))
{ {
@ -1049,6 +1061,8 @@ parse_escaped(
&Handler::on_key_part : &Handler::on_string_part; &Handler::on_key_part : &Handler::on_string_part;
constexpr auto ev_too_large = IsKey ? constexpr auto ev_too_large = IsKey ?
error::key_too_large : error::string_too_large; error::key_too_large : error::string_too_large;
constexpr auto max_size = IsKey ?
Handler::max_key_size : Handler::max_string_size;
detail::clipped_const_stream cs(p, end_); detail::clipped_const_stream cs(p, end_);
detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp; detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
int digit; int digit;
@ -1089,8 +1103,9 @@ do_str3:
{ {
if(BOOST_JSON_LIKELY(! temp.empty())) if(BOOST_JSON_LIKELY(! temp.empty()))
{ {
if(BOOST_JSON_UNLIKELY(temp.size() > BOOST_ASSERT(total <= max_size);
BOOST_JSON_MAX_STRING_SIZE - total)) if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large); return fail(cs.begin(), ev_too_large);
total += temp.size(); total += temp.size();
if(BOOST_JSON_UNLIKELY( if(BOOST_JSON_UNLIKELY(
@ -1238,8 +1253,9 @@ do_str3:
// flush // flush
if(BOOST_JSON_LIKELY(! temp.empty())) if(BOOST_JSON_LIKELY(! temp.empty()))
{ {
if(BOOST_JSON_UNLIKELY(temp.size() > BOOST_ASSERT(total <= max_size);
BOOST_JSON_MAX_STRING_SIZE - total)) if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large); return fail(cs.begin(), ev_too_large);
total += temp.size(); total += temp.size();
if(BOOST_JSON_UNLIKELY( if(BOOST_JSON_UNLIKELY(
@ -1367,8 +1383,9 @@ do_str2:
// flush // flush
if(BOOST_JSON_LIKELY(! temp.empty())) if(BOOST_JSON_LIKELY(! temp.empty()))
{ {
if(BOOST_JSON_UNLIKELY(temp.size() > BOOST_ASSERT(total <= max_size);
BOOST_JSON_MAX_STRING_SIZE - total)) if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large); return fail(cs.begin(), ev_too_large);
total += temp.size(); total += temp.size();
if(BOOST_JSON_UNLIKELY( if(BOOST_JSON_UNLIKELY(
@ -1383,8 +1400,9 @@ do_str2:
c = *cs; c = *cs;
if(BOOST_JSON_LIKELY(c == '\x22')) // '"' if(BOOST_JSON_LIKELY(c == '\x22')) // '"'
{ {
if(BOOST_JSON_UNLIKELY(temp.size() > BOOST_ASSERT(total <= max_size);
BOOST_JSON_MAX_STRING_SIZE - total)) if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large); return fail(cs.begin(), ev_too_large);
total += temp.size(); total += temp.size();
if(BOOST_JSON_UNLIKELY( if(BOOST_JSON_UNLIKELY(
@ -1400,8 +1418,9 @@ do_str2:
{ {
if(BOOST_JSON_LIKELY(! temp.empty())) if(BOOST_JSON_LIKELY(! temp.empty()))
{ {
if(BOOST_JSON_UNLIKELY(temp.size() > BOOST_ASSERT(total <= max_size);
BOOST_JSON_MAX_STRING_SIZE - total)) if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large); return fail(cs.begin(), ev_too_large);
total += temp.size(); total += temp.size();
if(BOOST_JSON_UNLIKELY( if(BOOST_JSON_UNLIKELY(
@ -1512,7 +1531,7 @@ do_obj2:
} }
loop: loop:
if(BOOST_JSON_UNLIKELY(++size > if(BOOST_JSON_UNLIKELY(++size >
BOOST_JSON_MAX_STRUCTURED_SIZE)) Handler::max_object_size))
return fail(cs.begin(), error::object_too_large); return fail(cs.begin(), error::object_too_large);
do_obj3: do_obj3:
cs = parse_string<StackEmpty, true, cs = parse_string<StackEmpty, true,
@ -1658,7 +1677,7 @@ do_arr2:
} }
loop: loop:
if(BOOST_JSON_UNLIKELY(++size > if(BOOST_JSON_UNLIKELY(++size >
BOOST_JSON_MAX_STRUCTURED_SIZE)) Handler::max_array_size))
return fail(cs.begin(), error::array_too_large); return fail(cs.begin(), error::array_too_large);
do_arr3: do_arr3:
// array is not empty, value required // array is not empty, value required

View File

@ -54,10 +54,7 @@ public:
static static
constexpr constexpr
std::size_t std::size_t
max_size() noexcept max_size() noexcept;
{
return BOOST_JSON_MAX_STRUCTURED_SIZE;
}
value* value*
data() const noexcept data() const noexcept

View File

@ -83,6 +83,24 @@ BOOST_JSON_NS_BEGIN
the error code to a suitable value. This error the error code to a suitable value. This error
code will be returned by the write function to code will be returned by the write function to
the caller. the caller.
\n
Handlers must also define the following
static data members:
@li `max_object_size`, the maximum number
of elements an object can contain,
@li `max_array_size`, the maximum number
of elements an array can contain,
@li `max_key_size`, the maximum length
for object keys, and
@li `max_string_size`, the maximum
length for strings.
If a value exceeding these limits
is encountered, parsing fails.
\n \n
The following declaration meets the parser's The following declaration meets the parser's
handler requirements: handler requirements:
@ -90,6 +108,12 @@ BOOST_JSON_NS_BEGIN
@code @code
struct handler struct handler
{ {
/// Value size limits
constexpr static std::size_t max_object_size = -1;
constexpr static std::size_t max_array_size = -1;
constexpr static std::size_t max_key_size = -1;
constexpr static std::size_t max_string_size = -1;
/// Called once when the JSON parsing begins. /// Called once when the JSON parsing begins.
/// ///
/// @return `true` on success. /// @return `true` on success.

View File

@ -13,6 +13,18 @@
BOOST_JSON_NS_BEGIN BOOST_JSON_NS_BEGIN
namespace detail { namespace detail {
constexpr
std::size_t
array_impl::
max_size() noexcept
{
// max_size depends on the address model
using min = std::integral_constant<std::size_t,
(std::size_t(-1) - sizeof(table)) / sizeof(value)>;
return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
}
auto auto
array_impl:: array_impl::
index_of(value const* pos) const noexcept -> index_of(value const* pos) const noexcept ->

View File

@ -21,16 +21,14 @@ array_impl(
std::size_t capacity, std::size_t capacity,
storage_ptr const& sp) storage_ptr const& sp)
{ {
auto constexpr soft_limit = if(capacity > max_size())
(std::size_t(-1) - sizeof(table)) /
sizeof(value);
if( capacity > soft_limit ||
capacity > max_size())
detail::throw_length_error( detail::throw_length_error(
"array too large", "capacity > max_size()",
BOOST_CURRENT_LOCATION); BOOST_CURRENT_LOCATION);
if(capacity > 0) if(capacity > 0)
{ {
// make sure to update max_size
// if this is changed
tab_ = ::new(sp->allocate( tab_ = ::new(sp->allocate(
(sizeof(table) + (sizeof(table) +
capacity * sizeof(value) + capacity * sizeof(value) +

View File

@ -16,6 +16,19 @@
BOOST_JSON_NS_BEGIN BOOST_JSON_NS_BEGIN
namespace detail { namespace detail {
constexpr
std::size_t
object_impl::
max_size() noexcept
{
// max_size depends on the address model
using min = std::integral_constant<std::size_t,
(std::size_t(-1) - sizeof(table)) /
(sizeof(value_type) + sizeof(index_t))>;
return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
}
void void
object_impl:: object_impl::
remove( remove(
@ -41,7 +54,7 @@ bucket_sizes() noexcept ->
{ {
// Taken from Boost.Intrusive and Boost.MultiIndex code, // Taken from Boost.Intrusive and Boost.MultiIndex code,
// thanks to Ion Gaztanaga and Joaquin M Lopez Munoz. // thanks to Ion Gaztanaga and Joaquin M Lopez Munoz.
static constexpr std::size_t list[33] = static constexpr std::size_t list[34] =
{ {
0, 0,
@ -61,7 +74,9 @@ bucket_sizes() noexcept ->
100663319, 201326611, 100663319, 201326611,
402653189, 805306457, 402653189, 805306457,
1610612741, 1610612741,
BOOST_JSON_MAX_STRUCTURED_SIZE // 3221225473 BOOST_JSON_MAX_STRUCTURED_SIZE,
// catch anything that exceeds max_size
std::size_t(-1)
}; };
return list; return list;
} }

View File

@ -37,14 +37,12 @@ object_impl(
std::uintptr_t salt, std::uintptr_t salt,
storage_ptr const& sp) storage_ptr const& sp)
{ {
// max capacity based on address model if(capacity > max_size())
auto constexpr soft_limit =
(std::size_t(-1) - sizeof(table)) / (
sizeof(value_type) + sizeof(index_t));
if(capacity > soft_limit)
throw_length_error( throw_length_error(
"capacity > soft_limit", "capacity > max_size()",
BOOST_CURRENT_LOCATION); BOOST_CURRENT_LOCATION);
// make sure to update max_size
// if this is changed
const auto n = const auto n =
sizeof(table) + sizeof(table) +
capacity * capacity *

View File

@ -31,7 +31,7 @@ class object_impl
using index_t = std::uint32_t; using index_t = std::uint32_t;
static index_t const null_index = static index_t const null_index =
std::uint32_t(-1); std::uint32_t(-1);
using bucket_size_array = const std::size_t [33]; using bucket_size_array = const std::size_t[34];
BOOST_JSON_DECL BOOST_JSON_DECL
void void
@ -62,6 +62,11 @@ public:
do_destroy(sp); do_destroy(sp);
} }
static
constexpr
std::size_t
max_size() noexcept;
std::size_t std::size_t
size() const noexcept size() const noexcept
{ {

View File

@ -97,7 +97,11 @@ public:
std::size_t std::size_t
max_size() noexcept max_size() noexcept
{ {
return BOOST_JSON_MAX_STRING_SIZE; // max_size depends on the address model
using min = std::integral_constant<std::size_t,
std::size_t(-1) - sizeof(table)>;
return min::value < BOOST_JSON_MAX_STRING_SIZE ?
min::value : BOOST_JSON_MAX_STRING_SIZE;
} }
BOOST_JSON_DECL BOOST_JSON_DECL

View File

@ -212,10 +212,6 @@ reserve(std::size_t new_capacity)
{ {
if(new_capacity <= capacity()) if(new_capacity <= capacity())
return; return;
if(new_capacity > max_size())
detail::throw_length_error(
"new_capacity > max_size()",
BOOST_CURRENT_LOCATION);
rehash(new_capacity); rehash(new_capacity);
} }

View File

@ -509,12 +509,12 @@ rehash(std::size_t new_capacity)
BOOST_ASSERT(new_capacity > capacity()); BOOST_ASSERT(new_capacity > capacity());
std::size_t const* prime = std::size_t const* prime =
object_impl::bucket_sizes(); object_impl::bucket_sizes();
while(new_capacity > *prime) while(*prime < new_capacity)
++prime; ++prime;
new_capacity = *prime; new_capacity = *prime;
if(new_capacity > max_size()) if(new_capacity > max_size())
detail::throw_length_error( detail::throw_length_error(
"object too large", "new_capacity > max_size()",
BOOST_CURRENT_LOCATION); BOOST_CURRENT_LOCATION);
object_impl impl( object_impl impl(
new_capacity, new_capacity,

View File

@ -860,7 +860,7 @@ public:
std::size_t std::size_t
max_size() noexcept max_size() noexcept
{ {
return BOOST_JSON_MAX_STRUCTURED_SIZE; return object_impl::max_size();
} }
/** Return the number of elements that can be held in currently allocated memory /** Return the number of elements that can be held in currently allocated memory

View File

@ -104,6 +104,18 @@ class parser
{ {
struct handler struct handler
{ {
constexpr static std::size_t
max_object_size = object::max_size();
constexpr static std::size_t
max_array_size = array::max_size();
constexpr static std::size_t
max_key_size = string::max_size();
constexpr static std::size_t
max_string_size = string::max_size();
value_stack st; value_stack st;
template<class... Args> template<class... Args>

View File

@ -62,6 +62,8 @@ class string
friend struct detail::value_access; friend struct detail::value_access;
#endif #endif
using string_impl = detail::string_impl;
inline inline
string( string(
char** key, char** key,
@ -130,7 +132,7 @@ private:
char>::value>::type; char>::value>::type;
storage_ptr sp_; // must come first storage_ptr sp_; // must come first
detail::string_impl impl_; string_impl impl_;
public: public:
/** Destructor. /** Destructor.
@ -190,7 +192,7 @@ public:
: sp_(std::move(other.get().sp_)) : sp_(std::move(other.get().sp_))
, impl_(other.get().impl_) , impl_(other.get().impl_)
{ {
::new(&other.get().impl_) detail::string_impl(); ::new(&other.get().impl_) string_impl();
} }
/** Constructor. /** Constructor.
@ -437,7 +439,7 @@ public:
: sp_(other.sp_) : sp_(other.sp_)
, impl_(other.impl_) , impl_(other.impl_)
{ {
::new(&other.impl_) detail::string_impl(); ::new(&other.impl_) string_impl();
} }
/** Constructor. /** Constructor.
@ -1433,7 +1435,7 @@ public:
std::size_t std::size_t
max_size() noexcept max_size() noexcept
{ {
return BOOST_JSON_MAX_STRING_SIZE; return string_impl::max_size();
} }
/** Return the number of characters that can be held without a reallocation. /** Return the number of characters that can be held without a reallocation.

View File

@ -872,37 +872,15 @@ public:
good_one(s); good_one(s);
} }
void
testComments()
{
parse_options disabled;
parse_options enabled;
enabled.allow_comments = true;
const auto replace_and_test =
[&](string_view s)
{
static std::vector<string_view> comments =
{
"//\n",
"// \n",
"//aaaa\n",
"// aaaa\n",
"// /* \n",
"// /**/ \n",
"/**/",
"/*//*/",
"/*/*/",
"/******/",
"/*** ***/",
"/**aaaa***/",
"/*** aaaa***/"
};
class comment_parser class comment_parser
{ {
struct handler struct handler
{ {
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::string captured = ""; std::string captured = "";
bool on_document_begin( error_code& ) { return true; } bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; } bool on_document_end( error_code& ) { return true; }
@ -960,6 +938,33 @@ public:
} }
}; };
void
testComments()
{
parse_options disabled;
parse_options enabled;
enabled.allow_comments = true;
const auto replace_and_test =
[&](string_view s)
{
static std::vector<string_view> comments =
{
"//\n",
"// \n",
"//aaaa\n",
"// aaaa\n",
"// /* \n",
"// /**/ \n",
"/**/",
"/*//*/",
"/*/*/",
"/******/",
"/*** ***/",
"/**aaaa***/",
"/*** aaaa***/"
};
std::string formatted = ""; std::string formatted = "";
std::string just_comments = ""; std::string just_comments = "";
std::size_t guess = std::count( std::size_t guess = std::count(
@ -1064,6 +1069,73 @@ public:
good("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{},},},},},},}", enabled); good("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{},},},},},},}", enabled);
} }
class utf8_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::string captured = "";
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view sv, std::size_t, error_code& )
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_string( string_view sv, std::size_t, error_code& )
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_number_part( string_view, error_code&) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part( string_view, error_code& ) { return true; }
bool on_comment( string_view, error_code& ) { return true; }
};
basic_parser<handler> p_;
public:
utf8_parser()
: p_(parse_options())
{
}
std::size_t
write(
bool more,
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write(
more, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
}
string_view
captured() const noexcept
{
return p_.handler().captured;
}
};
void void
testUTF8Validation() testUTF8Validation()
{ {
@ -1228,68 +1300,6 @@ public:
bad("\"\\n\xf4\x80\x70\x80----------\""); bad("\"\\n\xf4\x80\x70\x80----------\"");
bad("\"\\n\xf4\x80\xbf\x70-\\n\xf4\x80\xbf\x70\""); bad("\"\\n\xf4\x80\xbf\x70-\\n\xf4\x80\xbf\x70\"");
class utf8_parser
{
struct handler
{
std::string captured = "";
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view sv, std::size_t, error_code& )
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_string( string_view sv, std::size_t, error_code& )
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_number_part( string_view, error_code&) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part( string_view, error_code& ) { return true; }
bool on_comment( string_view, error_code& ) { return true; }
};
basic_parser<handler> p_;
public:
utf8_parser()
: p_(parse_options())
{
}
std::size_t
write(
bool more,
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write(
more, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
}
string_view
captured() const noexcept
{
return p_.handler().captured;
}
};
const auto check = const auto check =
[this](string_view expected) [this](string_view expected)
{ {
@ -1360,15 +1370,16 @@ public:
} }
} }
void
testNumberLiteral()
{
class literal_parser class literal_parser
{ {
struct handler struct handler
{ {
std::string captured = ""; constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::string captured = "";
bool on_document_begin( error_code& ) { return true; } bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; } bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; } bool on_object_begin( error_code& ) { return true; }
@ -1437,6 +1448,9 @@ public:
} }
}; };
void
testNumberLiteral()
{
const auto check = const auto check =
[](string_view expected) [](string_view expected)
{ {

View File

@ -286,14 +286,8 @@ public:
auto jv = parse(s, ec); auto jv = parse(s, ec);
BOOST_TEST(! ec); BOOST_TEST(! ec);
} }
}
void
testBasicParser()
{
// overflow in on_key_part // overflow in on_key_part
{ {
null_parser p;
error_code ec; error_code ec;
std::string big; std::string big;
big = "\\b"; big = "\\b";
@ -301,13 +295,12 @@ public:
string::max_size()*2, '*'); string::max_size()*2, '*');
auto const js = auto const js =
"{\"" + big + "\":null}"; "{\"" + big + "\":null}";
p.write(js.data(), js.size(), ec); auto jv = parse(js, ec);
BOOST_TEST(ec == error::key_too_large); BOOST_TEST(ec == error::key_too_large);
} }
// overflow in on_key // overflow in on_key
{ {
null_parser p;
error_code ec; error_code ec;
std::string big; std::string big;
big = "\\b"; big = "\\b";
@ -315,13 +308,12 @@ public:
(string::max_size()*3)/2, '*'); (string::max_size()*3)/2, '*');
auto const js = auto const js =
"{\"" + big + "\":null}"; "{\"" + big + "\":null}";
p.write(js.data(), js.size(), ec); auto jv = parse(js, ec);
BOOST_TEST(ec == error::key_too_large); BOOST_TEST(ec == error::key_too_large);
} }
// overflow in on_string_part // overflow in on_string_part
{ {
null_parser p;
error_code ec; error_code ec;
std::string big; std::string big;
big = "\\b"; big = "\\b";
@ -329,13 +321,12 @@ public:
string::max_size()*2, '*'); string::max_size()*2, '*');
auto const js = auto const js =
"\"" + big + "\""; "\"" + big + "\"";
p.write(js.data(), js.size(), ec); auto jv = parse(js, ec);
BOOST_TEST(ec == error::string_too_large); BOOST_TEST(ec == error::string_too_large);
} }
// overflow in on_string // overflow in on_string
{ {
null_parser p;
error_code ec; error_code ec;
std::string big; std::string big;
big = "\\b"; big = "\\b";
@ -343,14 +334,13 @@ public:
(string::max_size()*3)/2, '*'); (string::max_size()*3)/2, '*');
auto const js = auto const js =
"\"" + big + "\""; "\"" + big + "\"";
p.write(js.data(), js.size(), ec); auto jv = parse(js, ec);
BOOST_TEST(ec == error::string_too_large); BOOST_TEST(ec == error::string_too_large);
} }
// object overflow // object overflow
{ {
null_parser p;
error_code ec; error_code ec;
string_view s = R"({ string_view s = R"({
"00":0,"01":0,"02":0,"03":0,"04":0,"05":0,"06":0,"07":0,"08":0,"09":0, "00":0,"01":0,"02":0,"03":0,"04":0,"05":0,"06":0,"07":0,"08":0,"09":0,
@ -358,20 +348,19 @@ public:
"20":0 "20":0
})"; })";
p.write(s.data(), s.size(), ec); auto jv = parse(s, ec);
BOOST_TEST(ec == error::object_too_large); BOOST_TEST(ec == error::object_too_large);
} }
// array overflow // array overflow
{ {
null_parser p;
error_code ec; error_code ec;
string_view s = "[" string_view s = "["
"0,0,0,0,0,0,0,0,0,0," "0,0,0,0,0,0,0,0,0,0,"
"0,0,0,0,0,0,0,0,0,0," "0,0,0,0,0,0,0,0,0,0,"
"0" "0"
"]"; "]";
p.write(s.data(), s.size(), ec); auto jv = parse(s, ec);
BOOST_TEST(ec == error::array_too_large); BOOST_TEST(ec == error::array_too_large);
} }
} }
@ -390,7 +379,6 @@ public:
testString(); testString();
testStack(); testStack();
testParser(); testParser();
testBasicParser();
#else #else
BOOST_TEST_PASS(); BOOST_TEST_PASS();

View File

@ -145,6 +145,11 @@ class null_parser
{ {
struct handler struct handler
{ {
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
bool on_document_begin( error_code& ) { return true; } bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; } bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; } bool on_object_begin( error_code& ) { return true; }
@ -205,6 +210,11 @@ class fail_parser
{ {
struct handler struct handler
{ {
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::size_t n; std::size_t n;
handler() handler()
@ -445,6 +455,11 @@ class throw_parser
{ {
struct handler struct handler
{ {
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::size_t n; std::size_t n;
handler() handler()

View File

@ -1640,13 +1640,7 @@ public:
check_array(value{false,2}, false, 2); check_array(value{false,2}, false, 2);
check_array(value{false,2,"3",nullptr}, false, 2, "3", nullptr); check_array(value{false,2,"3",nullptr}, false, 2, "3", nullptr);
check_array(value{2,false,"3"}, 2, false, "3"); check_array(value{2,false,"3"}, 2, false, "3");
check_array(value{true,2,"3"}, true, 2, "3"); } check_array(value{true,2,"3"}, true, 2, "3");
void
testMaxSize()
{
// The implementation requires these equal
BOOST_TEST(object::max_size() == array::max_size());
} }
//------------------------------------------------------ //------------------------------------------------------
@ -1667,7 +1661,6 @@ public:
testKeyValuePair(); testKeyValuePair();
testStdConstruction(); testStdConstruction();
testInitList(); testInitList();
testMaxSize();
} }
}; };