Skip to content

Commit

Permalink
external_constructor<std::valarray>: Handle empty array properly
Browse files Browse the repository at this point in the history
Clang UBSAN complains with the following message when an empty std::valarray is passed in:

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/valarray:571:14 in

2/2 Test nlohmann#68: test-regression_all ..............***Failed    4.68 sec
/usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/valarray:571:14: runtime error: reference binding to null pointer of type 'const do
uble'
    #0 0x6fbe57 in std::valarray<double>::operator[](unsigned long) const /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/valarray:
571:7
    nlohmann#1 0x6fbe57 in double const* std::begin<double>(std::valarray<double> const&) /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/v
alarray:1207
    nlohmann#2 0x6fbe57 in void nlohmann::detail::external_constructor<(nlohmann::detail::value_t)2>::construct<nlohmann::basic_json<std::map, std::vector, s
td::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_seri
alizer>, double, 0>(nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool
, long, unsigned long, double, std::allocator, nlohmann::adl_serializer>&, std::valarray<double> const&) /home/firma/devel/json/include/nlohmann/deta
il/conversions/to_json.hpp:157
    nlohmann#3 0x5e3fe3 in void nlohmann::detail::to_json<nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>
, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer>, double, 0>(nlohmann::basic_json<std::map, std
::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohman
n::adl_serializer>&, std::valarray<double> const&) /home/firma/devel/json/include/nlohmann/detail/conversions/to_json.hpp:270:5
    nlohmann#4 0x5e3fe3 in decltype((to_json(fp, std::forward<std::valarray<double>&>(fp0))) , ((void)())) nlohmann::detail::to_json_fn::operator()<nlohmann:
:basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double
, std::allocator, nlohmann::adl_serializer>, std::valarray<double>&>(nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std
::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer>&, std::valarray<double>&) c
onst /home/firma/devel/json/include/nlohmann/detail/conversions/to_json.hpp:334
    nlohmann#5 0x5e3fe3 in decltype((nlohmann::(anonymous namespace)::to_json(fp, std::forward<std::valarray<double>&>(fp0))) , ((void)())) nlohmann::adl_ser
ializer<std::valarray<double>, void>::to_json<nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, st
d::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer>, std::valarray<double>&>(nlohmann::basic_json<std:
:map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator
, nlohmann::adl_serializer>&, std::valarray<double>&) /home/firma/devel/json/include/nlohmann/adl_serializer.hpp:45
    nlohmann#6 0x5e3fe3 in nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool,
 long, unsigned long, double, std::allocator, nlohmann::adl_serializer>::basic_json<std::valarray<double>&, std::valarray<double>, 0>(std::valarray<d
ouble>&) /home/firma/devel/json/include/nlohmann/json.hpp:1257
    nlohmann#7 0x5e3fe3 in _DOCTEST_ANON_FUNC_2() /home/firma/devel/json/test/src/unit-regression.cpp:1377
    nlohmann#8 0x77313e in doctest::Context::run() /home/firma/devel/json/test/thirdparty/doctest/doctest.h:5938:21
    nlohmann#9 0x777ae0 in main /home/firma/devel/json/test/thirdparty/doctest/doctest.h:6016:71
    nlohmann#10 0x7fae220532e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
    nlohmann#11 0x4a6479 in _start (/home/firma/devel/json/build/test/test-regression+0x4a6479)

The important thing to note here is that a std::valarray is *not* a STL
container, so the usual containter and iterator semantics don't apply.

Therefore we have to check if the container is non-empty before.
  • Loading branch information
t-b committed Aug 30, 2019
1 parent 20171e2 commit 5d83e5e
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 4 deletions.
7 changes: 5 additions & 2 deletions include/nlohmann/detail/conversions/to_json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,11 @@ struct external_constructor<value_t::array>
{
j.m_type = value_t::array;
j.m_value = value_t::array;
j.m_value.array->resize(arr.size());
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
if (arr.size() > 0)
{
j.m_value.array->resize(arr.size());
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
}
j.assert_invariant();
}
};
Expand Down
7 changes: 5 additions & 2 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3488,8 +3488,11 @@ struct external_constructor<value_t::array>
{
j.m_type = value_t::array;
j.m_value = value_t::array;
j.m_value.array->resize(arr.size());
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
if (arr.size() > 0)
{
j.m_value.array->resize(arr.size());
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
}
j.assert_invariant();
}
};
Expand Down

0 comments on commit 5d83e5e

Please sign in to comment.