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

Fix return value of get_ptr for unsigned integers #4525

Merged
merged 2 commits into from
Dec 6, 2024
Merged
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
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
Loading