Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow extra members for converted structs #1056

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def main(ctx):
linux_cxx("Clang 12 arm64", "clang++-12", packages="clang-12 libstdc++-9-dev", llvm_os="focal", llvm_ver="12", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={'B2_TOOLSET': 'clang-12', 'B2_CXXSTD': '17,20', 'DRONE_JOB_UUID': '7719a1c783m'}, arch="arm64", globalenv=globalenv),
linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '17,2a', 'DRONE_JOB_UUID': '0716d9708dm'}, arch="arm64", globalenv=globalenv),
linux_cxx("docs", "g++", packages="docbook docbook-xml docbook-xsl python3-jinja2 xsltproc flex libfl-dev bison unzip rsync", buildtype="docs", buildscript="drone", image="cppalliance/droneubuntu1804:1", environment={'COMMENT': 'docs', 'DRONE_JOB_UUID': 'b6589fc6ab'}, globalenv=globalenv),
linux_cxx("codecov", "g++-8", packages="g++-8", buildtype="codecov", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'codecov.io', 'LCOV_BRANCH_COVERAGE': '0', 'B2_CXXSTD': '11', 'B2_TOOLSET': 'gcc-8', 'B2_DEFINES': 'BOOST_JSON_EXPENSIVE_TESTS BOOST_NO_STRESS_TEST=1', 'CODECOV_TOKEN': {'from_secret': 'codecov_token'}, 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv),
linux_cxx("codecov", "g++-8", packages="g++-8", buildtype="codecov", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'codecov.io', 'LCOV_BRANCH_COVERAGE': '0', 'B2_CXXSTD': '17', 'B2_TOOLSET': 'gcc-8', 'B2_DEFINES': 'BOOST_JSON_EXPENSIVE_TESTS BOOST_NO_STRESS_TEST=1', 'CODECOV_TOKEN': {'from_secret': 'codecov_token'}, 'B2_FLAGS': 'warnings=extra warnings-as-errors=on linkflags=-lstdc++fs', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv),
linux_cxx("Valgrind", "clang++-14", packages="clang-14 libc6-dbg libc++-dev libstdc++-9-dev", llvm_os="jammy", llvm_ver="14", buildscript="drone", buildtype="valgrind", image="cppalliance/droneubuntu2204:1", environment={'COMMENT': 'valgrind', 'B2_TOOLSET': 'clang-14', 'B2_CXXSTD': '11,14,17', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_VARIANT': 'debug', 'B2_TESTFLAGS': 'testing.launcher=valgrind', 'VALGRIND_OPTS': '--error-exitcode=1'}, globalenv=globalenv),
linux_cxx("ASan GCC", "g++-12", packages="g++-12", buildscript="drone", buildtype="boost", image="cppalliance/droneubuntu2204:1", environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-12', 'B2_CXXSTD': '11,14,17', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True'}, globalenv=globalenv, privileged=True),
linux_cxx("ASan Clang", "clang++-14", packages="clang-14 libstdc++-10-dev", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2204:1", environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'clang-14', 'B2_CXXSTD': '11,14,17', 'B2_ASAN': '1', 'B2_DEFINES': 'define=BOOST_NO_STRESS_TEST=1'}, globalenv=globalenv, privileged=True),
Expand Down
13 changes: 13 additions & 0 deletions fuzzing/fuzz_direct_parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@
// Official repository: https://github.com/boostorg/json
//

#include <boost/json.hpp>

#if !defined(BOOST_DESCRIBE_CXX14)

#include <boost/config/pragma_message.hpp>

BOOST_PRAGMA_MESSAGE( "This example requires C++14" )

int main() {}

#else

#include <boost/json/parse_into.hpp>
#include <boost/variant2/variant.hpp>
#include <boost/describe.hpp>
Expand Down Expand Up @@ -82,3 +94,4 @@ LLVMFuzzerTestOneInput(
return 0;
}

#endif // !defined(BOOST_DESCRIBE_CXX14)
209 changes: 167 additions & 42 deletions include/boost/json/detail/parse_into.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,19 +711,19 @@ struct handler_tuple;

template< class P, template<class...> class L, class... V, std::size_t... I >
struct handler_tuple< P, L<V...>, mp11::index_sequence<I...> >
: handler_tuple_element< I, get_handler<V, P> >
: handler_tuple_element<I, V>
...
{
handler_tuple( handler_tuple const& ) = delete;
handler_tuple& operator=( handler_tuple const& ) = delete;

template< class Access, class T >
handler_tuple( Access access, T* pv, P* pp )
: handler_tuple_element< I, get_handler<V, P> >(
access( pv, mp11::mp_int<I>() ),
: handler_tuple_element<I, V>(
access( pv, mp11::mp_size_t<I>() ),
pp )
...
{ }
{}
};

#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
Expand Down Expand Up @@ -803,10 +803,17 @@ class converting_handler<tuple_conversion_tag, T, P>
{

private:
using ElementTypes = tuple_element_list<T>;

template<class V>
using ElementHandler = get_handler<V, converting_handler>;
using InnerHandlers = mp11::mp_transform<ElementHandler, ElementTypes>;
using HandlerTuple = handler_tuple<converting_handler, InnerHandlers>;

T* value_;
P* parent_;

handler_tuple< converting_handler, tuple_element_list<T> > handlers_;
HandlerTuple handlers_;
int inner_active_ = -1;

public:
Expand Down Expand Up @@ -874,7 +881,7 @@ class converting_handler<tuple_conversion_tag, T, P>

struct do_on_array_begin
{
handler_tuple< converting_handler, tuple_element_list<T> >& handlers;
HandlerTuple& handlers;
system::error_code& ec;

template< class I >
Expand Down Expand Up @@ -905,7 +912,7 @@ class converting_handler<tuple_conversion_tag, T, P>

struct do_on_array_end
{
handler_tuple< converting_handler, tuple_element_list<T> >& handlers;
HandlerTuple& handlers;
system::error_code& ec;

template< class I >
Expand Down Expand Up @@ -966,6 +973,13 @@ using struct_element_list = mp11::mp_transform_q<

struct struct_accessor
{
template< class T >
auto operator()( T*, mp11::mp_size< described_members<T> > ) const
-> void*
{
return nullptr;
}

template< class T, class I >
auto operator()( T* t, I ) const
-> described_member_t<T, mp11::mp_at< described_members<T>, I> >*
Expand All @@ -976,16 +990,132 @@ struct struct_accessor
}
};

template< class F >
struct struct_key_searcher
{
F fn;
string_view key;
int& found;
int index = 0;

struct_key_searcher(string_view key, int& found) noexcept
: key(key), found(found)
{}

template< class D >
void
operator()( D ) const
operator()( D )
{
fn( D::name ) ;
if( key == D::name )
found = index;
++index;
}
};

template<class P>
struct ignoring_handler
{
P* parent_;
std::size_t array_depth_ = 0;
std::size_t object_depth_ = 0;

ignoring_handler(ignoring_handler const&) = delete;
ignoring_handler& operator=(ignoring_handler const&) = delete;

ignoring_handler(void*, P* p) noexcept
: parent_(p)
{}

bool on_object_begin(system::error_code&)
{
++object_depth_;
return true;
}

bool on_object_end(system::error_code& ec)
{
BOOST_ASSERT( object_depth_ > 0 );
--object_depth_;

if( (array_depth_ + object_depth_) == 0 )
return parent_->signal_value(ec);
return true;
}

bool on_array_begin(system::error_code&)
{
++array_depth_;
return true;
}

bool on_array_end(system::error_code& ec)
{
BOOST_ASSERT( array_depth_ > 0 );
--array_depth_;

if( (array_depth_ + object_depth_) == 0 )
return parent_->signal_end(ec);
return true;
}

bool on_key_part(system::error_code&, string_view)
{
return true;
}

bool on_key(system::error_code&, string_view)
{
return true;
}

bool on_string_part(system::error_code&, string_view)
{
return true;
}

bool on_string(system::error_code& ec, string_view)
{
if( (array_depth_ + object_depth_) == 0 )
return parent_->signal_value(ec);
return true;
}

bool on_number_part(system::error_code&)
{
return true;
}

bool on_int64(system::error_code& ec, std::int64_t)
{
if( (array_depth_ + object_depth_) == 0 )
return parent_->signal_value(ec);
return true;
}

bool on_uint64(system::error_code& ec, std::uint64_t)
{
if( (array_depth_ + object_depth_) == 0 )
return parent_->signal_value(ec);
return true;
}

bool on_double(system::error_code& ec, double)
{
if( (array_depth_ + object_depth_) == 0 )
return parent_->signal_value(ec);
return true;
}

bool on_bool(system::error_code& ec, bool)
{
if( (array_depth_ + object_depth_) == 0 )
return parent_->signal_value(ec);
return true;
}

bool on_null(system::error_code& ec)
{
if( (array_depth_ + object_depth_) == 0 )
return parent_->signal_value(ec);
return true;
}
};

Expand All @@ -1000,14 +1130,22 @@ class converting_handler<described_class_conversion_tag, V, P>
#else

private:
using Dm = described_members<V>;
using Dt = struct_element_list<V>;

template<class T>
using MemberHandler = get_handler<T, converting_handler>;
using InnerHandlers = mp11::mp_push_back<
mp11::mp_transform<MemberHandler, Dt>,
ignoring_handler<converting_handler> >;
using InnerCount = mp11::mp_size<InnerHandlers>;

V* value_;
P* parent_;

std::string key_;

using Dm = described_members<V>;

handler_tuple< converting_handler, struct_element_list<V> > handlers_;
handler_tuple<converting_handler, InnerHandlers> handlers_;
int inner_active_ = -1;
std::size_t activated_ = 0;

Expand All @@ -1019,23 +1157,27 @@ class converting_handler<described_class_conversion_tag, V, P>
: value_(v), parent_(p), handlers_(struct_accessor(), v, this)
{}

struct is_optional_checker
struct is_required_checker
{
bool operator()( mp11::mp_size<Dt> ) const noexcept
{
return false;
}

template< class I >
bool operator()( I ) const noexcept
auto operator()( I ) const noexcept
{
using L = struct_element_list<V>;
using T = mp11::mp_at<L, I>;
using T = mp11::mp_at<Dt, I>;
return !is_optional_like<T>::value;
}
};

bool signal_value(system::error_code&)
{
BOOST_ASSERT( inner_active_ >= 0 );
bool required_member = mp11::mp_with_index< mp11::mp_size<Dm> >(
bool required_member = mp11::mp_with_index<InnerCount>(
inner_active_,
is_optional_checker{});
is_required_checker{});
if( required_member )
++activated_;

Expand All @@ -1060,7 +1202,7 @@ class converting_handler<described_class_conversion_tag, V, P>
auto f = [&](auto& handler) { return handler.fn ; }; \
using F = decltype(f); \
using H = decltype(handlers_); \
return mp11::mp_with_index< mp11::mp_size<Dm> >( \
return mp11::mp_with_index<InnerCount>( \
inner_active_, \
tuple_handler_op_invoker<H, F>{handlers_, f} );

Expand All @@ -1076,9 +1218,8 @@ class converting_handler<described_class_conversion_tag, V, P>
{
if( inner_active_ < 0 )
{
using L = struct_element_list<V>;
using C = mp11::mp_count_if<L, is_optional_like>;
constexpr int N = mp11::mp_size<L>::value - C::value;
using C = mp11::mp_count_if<Dt, is_optional_like>;
constexpr int N = mp11::mp_size<Dt>::value - C::value;
if( activated_ < N )
{
BOOST_JSON_FAIL( ec, error::size_mismatch );
Expand Down Expand Up @@ -1129,24 +1270,8 @@ class converting_handler<described_class_conversion_tag, V, P>
key = key_;
}

int i = 0;

auto f = [&](char const* name)
{
if( key == name )
inner_active_ = i;
++i;
};

mp11::mp_for_each<Dm>(
struct_key_searcher<decltype(f)>{f} );

if( inner_active_ < 0 )
{
BOOST_JSON_FAIL(ec, error::unknown_name);
return false;
}

inner_active_ = InnerCount::value - 1;
mp11::mp_for_each<Dm>( struct_key_searcher(key, inner_active_) );
return true;
}

Expand Down
Loading
Loading