From 971a8ec3f85bd359e37891f9f19263e31df361a2 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 30 Aug 2019 13:07:37 +0200 Subject: [PATCH] external_constructor: Handle empty array properly 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 #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::operator[](unsigned long) const /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/valarray: 571:7 #1 0x6fbe57 in double const* std::begin(std::valarray const&) /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/v alarray:1207 #2 0x6fbe57 in void nlohmann::detail::external_constructor<(nlohmann::detail::value_t)2>::construct, std::allocator >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_seri alizer>, double, 0>(nlohmann::basic_json, std::allocator >, bool , long, unsigned long, double, std::allocator, nlohmann::adl_serializer>&, std::valarray const&) /home/firma/devel/json/include/nlohmann/deta il/conversions/to_json.hpp:157 #3 0x5e3fe3 in void nlohmann::detail::to_json , std::allocator >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer>, double, 0>(nlohmann::basic_json, std::allocator >, bool, long, unsigned long, double, std::allocator, nlohman n::adl_serializer>&, std::valarray const&) /home/firma/devel/json/include/nlohmann/detail/conversions/to_json.hpp:270:5 #4 0x5e3fe3 in decltype((to_json(fp, std::forward&>(fp0))) , ((void)())) nlohmann::detail::to_json_fn::operator(), std::allocator >, bool, long, unsigned long, double , std::allocator, nlohmann::adl_serializer>, std::valarray&>(nlohmann::basic_json, std::allocator >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer>&, std::valarray&) c onst /home/firma/devel/json/include/nlohmann/detail/conversions/to_json.hpp:334 #5 0x5e3fe3 in decltype((nlohmann::(anonymous namespace)::to_json(fp, std::forward&>(fp0))) , ((void)())) nlohmann::adl_ser ializer, void>::to_json, st d::allocator >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer>, std::valarray&>(nlohmann::basic_json, std::allocator >, bool, long, unsigned long, double, std::allocator , nlohmann::adl_serializer>&, std::valarray&) /home/firma/devel/json/include/nlohmann/adl_serializer.hpp:45 #6 0x5e3fe3 in nlohmann::basic_json, std::allocator >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer>::basic_json&, std::valarray, 0>(std::valarray&) /home/firma/devel/json/include/nlohmann/json.hpp:1257 #7 0x5e3fe3 in _DOCTEST_ANON_FUNC_2() /home/firma/devel/json/test/src/unit-regression.cpp:1377 #8 0x77313e in doctest::Context::run() /home/firma/devel/json/test/thirdparty/doctest/doctest.h:5938:21 #9 0x777ae0 in main /home/firma/devel/json/test/thirdparty/doctest/doctest.h:6016:71 #10 0x7fae220532e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0) #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. --- include/nlohmann/detail/conversions/to_json.hpp | 5 ++++- single_include/nlohmann/json.hpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index db9eaf2bd2..c3ac5aa8f5 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -154,7 +154,10 @@ struct external_constructor 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) + { + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + } j.assert_invariant(); } }; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index ec5f70318b..671e4a8ecc 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3489,7 +3489,10 @@ struct external_constructor 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) + { + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + } j.assert_invariant(); } };