From c98f988ebec13a20e723cb8bfa6b6d5990088bb0 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 30 Nov 2024 17:27:20 +0100 Subject: [PATCH 1/2] :bug: fix return value of get_ptr for unsigned integers --- docs/mkdocs/docs/api/basic_json/get_ptr.md | 2 +- docs/mkdocs/docs/api/basic_json/get_ref.md | 2 +- include/nlohmann/json.hpp | 4 ++-- single_include/nlohmann/json.hpp | 4 ++-- tests/src/unit-pointer_access.cpp | 4 ++-- tests/src/unit-reference_access.cpp | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/mkdocs/docs/api/basic_json/get_ptr.md b/docs/mkdocs/docs/api/basic_json/get_ptr.md index 2441e1156e..a6bfec973d 100644 --- a/docs/mkdocs/docs/api/basic_json/get_ptr.md +++ b/docs/mkdocs/docs/api/basic_json/get_ptr.md @@ -35,7 +35,7 @@ Constant. !!! danger "Undefined behavior" - Writing data to the pointee of the result yields an undefined state. + The pointer becomes invalid if the underlying JSON object changes. ## Examples diff --git a/docs/mkdocs/docs/api/basic_json/get_ref.md b/docs/mkdocs/docs/api/basic_json/get_ref.md index b1219742ca..a978134051 100644 --- a/docs/mkdocs/docs/api/basic_json/get_ref.md +++ b/docs/mkdocs/docs/api/basic_json/get_ref.md @@ -40,7 +40,7 @@ Constant. !!! danger "Undefined behavior" - Writing data to the referee of the result yields an undefined state. + The reference becomes invalid if the underlying JSON object changes. ## Examples diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index e004e83082..763fd95783 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1463,13 +1463,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// get a pointer to the value (integer number) number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; } /// get a pointer to the value (integer number) constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; } /// get a pointer to the value (unsigned number) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 02441416bf..86d1cd3e88 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -20962,13 +20962,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// get a pointer to the value (integer number) number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; } /// get a pointer to the value (integer number) constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; } /// get a pointer to the value (unsigned number) diff --git a/tests/src/unit-pointer_access.cpp b/tests/src/unit-pointer_access.cpp index 6b1a6f8a83..b5734559bc 100644 --- a/tests/src/unit-pointer_access.cpp +++ b/tests/src/unit-pointer_access.cpp @@ -326,7 +326,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); @@ -355,7 +355,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); - CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); diff --git a/tests/src/unit-reference_access.cpp b/tests/src/unit-reference_access.cpp index e4cc2d5b2a..d63a470de0 100644 --- a/tests/src/unit-reference_access.cpp +++ b/tests/src/unit-reference_access.cpp @@ -215,8 +215,8 @@ TEST_CASE("reference access") "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); CHECK_THROWS_WITH_AS(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); - //CHECK_THROWS_WITH_AS(value.get_ref(), - // "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); + CHECK_THROWS_WITH_AS(value.get_ref(), + "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); CHECK_NOTHROW(value.get_ref()); CHECK_THROWS_WITH_AS(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&); } From c69d547650c8daf249558de029b4760b22f81d32 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 30 Nov 2024 19:33:35 +0100 Subject: [PATCH 2/2] :memo: update documentation --- docs/mkdocs/docs/api/basic_json/get_ptr.md | 32 ++++++++++++++++++++++ docs/mkdocs/docs/api/basic_json/get_ref.md | 4 +++ 2 files changed, 36 insertions(+) diff --git a/docs/mkdocs/docs/api/basic_json/get_ptr.md b/docs/mkdocs/docs/api/basic_json/get_ptr.md index a6bfec973d..b1ecf44d82 100644 --- a/docs/mkdocs/docs/api/basic_json/get_ptr.md +++ b/docs/mkdocs/docs/api/basic_json/get_ptr.md @@ -37,6 +37,34 @@ Constant. The pointer becomes invalid if the underlying JSON object changes. + Consider the following example code where the pointer `ptr` changes after the array is resized. As a result, reading or writing to `ptr` after the array change would be undefined behavior. The address of the first array element changes, because the underlying `std::vector` is resized after adding a fifth element. + + ```cpp + #include + #include + + using json = nlohmann::json; + + int main() + { + json j = {1, 2, 3, 4}; + auto* ptr = j[0].get_ptr(); + std::cout << "value at " << ptr << " is " << *ptr << std::endl; + + j.push_back(5); + + ptr = j[0].get_ptr(); + std::cout << "value at " << ptr << " is " << *ptr << std::endl; + } + ``` + + Output: + + ``` + value at 0x6000012fc1c8 is 1 + value at 0x6000029fc088 is 1 + ``` + ## Examples ??? example @@ -54,6 +82,10 @@ Constant. --8<-- "examples/get_ptr.output" ``` +## See also + +- [get_ref()](get_ref.md) get a reference value + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/get_ref.md b/docs/mkdocs/docs/api/basic_json/get_ref.md index a978134051..73b20b0e08 100644 --- a/docs/mkdocs/docs/api/basic_json/get_ref.md +++ b/docs/mkdocs/docs/api/basic_json/get_ref.md @@ -58,6 +58,10 @@ Constant. --8<-- "examples/get_ref.output" ``` +## See also + +- [get_ptr()](get_ptr.md) get a pointer value + ## Version history - Added in version 1.1.0.