Skip to content

merge_or_update behavior differs based on selected overload #755

Description

@shakedcsentinel

Describe the bug
The function merge_or_update in sorted_json_object.hpp overrides the wrong fields in the overload that takes rvalue reference. The overload that takes a const lvalue ref behaves as expected.
Source code link for latest commit to the file at the time of opening this bug:

void merge_or_update(const sorted_json_object& source)
{
for (auto it = source.begin(); it != source.end(); ++it)
{
insert_or_assign((*it).key(),(*it).value());
}
}
void merge_or_update(sorted_json_object&& source)
{
auto it = std::make_move_iterator(source.begin());
auto end = std::make_move_iterator(source.end());
for (; it != end; ++it)
{
auto pos = std::lower_bound(data_.begin(),data_.end(), (*it).key(),
Comp());
if (pos == data_.end())
{
data_.emplace_back(*it);
}
else
{
pos->value((*it).value());
}
}
}

The bug is that in the sorted_json_object&& overload, pos is searched using std::lower_bound, which returns the first element that should not appear before (*it).key(), but it does not check that it is actually that key before updating it.
For example, if I have a json object { "a": 5, "c": 19 } and I call merge_or_update with {"b":2} passed in a rvalue ref, the key b is not added to the json, rather the value of c changes to 2.
Again, the const sorted_json_object& behaves correctly.

merge_or_update should override the value of the correct key.

Passing an rvalue ref to merge_or_update removes existing keys if they don't exist in the input json.

Enumerate the steps to reproduce the bug
shown in example code

Include a small, self-contained example if possible

    const jsoncons::json source = jsoncons::json::parse(R"({"b":2})");

    jsoncons::json constRefTarget = jsoncons::json::parse(R"({"a":1,"c":3})");
    constRefTarget.merge_or_update(source);

    jsoncons::json rvalueTarget = jsoncons::json::parse(R"({"a":1,"c":3})");
    rvalueTarget.merge_or_update(jsoncons::json(source));

    std::cout << "expected:  {\"a\":1,\"b\":2,\"c\":3}\n";
    std::cout << "const&:    " << constRefTarget << "\n";
    std::cout << "&&:        " << rvalueTarget << "\n";

Output:

expected:  {"a":1,"b":2,"c":3}
const&:    {"a":1,"b":2,"c":3}
&&:        {"a":1,"c":2}

What compiler, architecture, and operating system?
Windows 11, x64, Visual Studio 18.10.1 build tools 14.51

  • Compiler: MSVC
  • Architecture (e.g. x86, x64) x64
  • Operating system: Windows

What jsoncons library version?

  • Latest release 1.10.0
  • Other release All releases from 0.99.8
  • master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions