Skip to content

Commit

Permalink
Fix return value of get_ptr for unsigned integers (#4525)
Browse files Browse the repository at this point in the history
* 🐛 fix return value of get_ptr for unsigned integers

* 📝 update documentation
  • Loading branch information
nlohmann authored Dec 6, 2024
1 parent a006a7a commit 9f60e85
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 10 deletions.
34 changes: 33 additions & 1 deletion docs/mkdocs/docs/api/basic_json/get_ptr.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,35 @@ 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.

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 <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
json j = {1, 2, 3, 4};
auto* ptr = j[0].get_ptr<std::int64_t*>();
std::cout << "value at " << ptr << " is " << *ptr << std::endl;

j.push_back(5);

ptr = j[0].get_ptr<std::int64_t*>();
std::cout << "value at " << ptr << " is " << *ptr << std::endl;
}
```

Output:

```
value at 0x6000012fc1c8 is 1
value at 0x6000029fc088 is 1
```

## Examples

Expand All @@ -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.
Expand Down
6 changes: 5 additions & 1 deletion docs/mkdocs/docs/api/basic_json/get_ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions tests/src/unit-pointer_access.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ TEST_CASE("pointer access")
CHECK(value.get_ptr<json::array_t*>() == nullptr);
CHECK(value.get_ptr<json::string_t*>() == nullptr);
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() != nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<json::number_unsigned_t*>() != nullptr);
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
CHECK(value.get_ptr<json::binary_t*>() == nullptr);
Expand Down Expand Up @@ -355,7 +355,7 @@ TEST_CASE("pointer access")
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() != nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_unsigned_t*>() != nullptr);
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
CHECK(value.get_ptr<const json::binary_t*>() == nullptr);
Expand Down
4 changes: 2 additions & 2 deletions tests/src/unit-reference_access.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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::boolean_t&>(),
"[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::number_integer_t&>(),
// "[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::number_integer_t&>(),
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
CHECK_NOTHROW(value.get_ref<json::number_unsigned_t&>());
CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
}
Expand Down

0 comments on commit 9f60e85

Please sign in to comment.