Skip to content

Commit d45b470

Browse files
committed
fix(json_wrapper): fix undefined behavior in copy constructor
The copy constructor was checking owns_json_ and json_ before they were initialized, causing undefined behavior. This fix initializes members before use in the member initializer list. Added unit tests to verify copy constructor behavior in various scenarios, including copying non-owning wrappers from operator[]. Signed-off-by: LHT129 <tianlan.lht@antgroup.com>
1 parent 5b12b90 commit d45b470

2 files changed

Lines changed: 64 additions & 7 deletions

File tree

src/json_wrapper.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,11 @@ JsonWrapper::~JsonWrapper() {
3030
}
3131
}
3232

33-
JsonWrapper::JsonWrapper(const JsonWrapper& other) {
34-
if (owns_json_) {
35-
delete json_;
36-
}
37-
json_ = new nlohmann::json();
38-
owns_json_ = true;
33+
JsonWrapper::JsonWrapper(const JsonWrapper& other) : json_(nullptr), owns_json_(true) {
3934
if (other.json_ != nullptr) {
40-
*json_ = *other.json_;
35+
json_ = new nlohmann::json(*other.json_);
36+
} else {
37+
json_ = new nlohmann::json();
4138
}
4239
}
4340

tests/test_json_wrapper.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2024-present the vsag project
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <catch2/catch_test_macros.hpp>
16+
17+
#include "json_wrapper.h"
18+
19+
TEST_CASE("JsonWrapper Copy Empty Wrapper", "[ft][json_wrapper]") {
20+
vsag::JsonWrapper w1;
21+
vsag::JsonWrapper w2 = w1;
22+
CHECK_FALSE(w2.Contains("any_key"));
23+
}
24+
25+
TEST_CASE("JsonWrapper Copy With String Data", "[ft][json_wrapper]") {
26+
auto w1 = vsag::JsonWrapper::Parse(R"({"key": "value"})");
27+
vsag::JsonWrapper w2 = w1;
28+
CHECK(w2.Contains("key"));
29+
CHECK(w2["key"].GetString() == "value");
30+
}
31+
32+
TEST_CASE("JsonWrapper Copy With Integer Data", "[ft][json_wrapper]") {
33+
auto w1 = vsag::JsonWrapper::Parse(R"({"num": 42})");
34+
vsag::JsonWrapper w2 = w1;
35+
CHECK(w2.Contains("num"));
36+
CHECK(w2["num"].GetInt() == 42);
37+
}
38+
39+
TEST_CASE("JsonWrapper Copy Independence", "[ft][json_wrapper]") {
40+
auto w1 = vsag::JsonWrapper::Parse(R"({"key": "value1"})");
41+
vsag::JsonWrapper w2 = w1;
42+
w2["key"].SetString("value2");
43+
CHECK(w1["key"].GetString() == "value1");
44+
CHECK(w2["key"].GetString() == "value2");
45+
}
46+
47+
TEST_CASE("JsonWrapper Copy Nested Json", "[ft][json_wrapper]") {
48+
auto w1 = vsag::JsonWrapper::Parse(R"({"outer": {"inner": "data"}})");
49+
vsag::JsonWrapper w2 = w1;
50+
CHECK(w2.Contains("outer"));
51+
CHECK(w2["outer"].Contains("inner"));
52+
CHECK(w2["outer"]["inner"].GetString() == "data");
53+
}
54+
55+
TEST_CASE("JsonWrapper Copy Non-owning Wrapper", "[ft][json_wrapper]") {
56+
auto w1 = vsag::JsonWrapper::Parse(R"({"valid": "json"})");
57+
vsag::JsonWrapper sub = w1["valid"];
58+
vsag::JsonWrapper w2 = sub;
59+
CHECK(w2.GetString() == "json");
60+
}

0 commit comments

Comments
 (0)