Skip to content

Commit dc7b50c

Browse files
authored
[fix](be) Avoid unsigned underflow in JSON modify path (#63579)
### What problem does this PR solve? Issue Number: None Problem Summary: JSON modify functions build a parent path by iterating to the element before the last JSON path leg. The loop used `get_leg_vector_size() - 1` on an unsigned size, which can underflow for an empty path expression even though normal root-path execution resolves to the root value before that branch. This patch caches the leg count once, asserts the non-empty invariant for the insert-parent branch, and uses `j + 1 < legs_count` to avoid unsigned subtraction while preserving behavior. The patch also adds BE unit coverage for missing-path JSONB modify cases where the parent path has to be rebuilt, including single-leg object insertion, nested object insertion, and array append behavior for both `jsonb_insert` and `jsonb_set`. ### Release note None ### Check List (For Author) - Test: - Unit Test: added `FunctionJsonbTEST.JsonbModifyMissingPathParent` - Build check: `DORIS_HOME=/mnt/disk7/hushenggang/doris-fix-spill ninja -C be/ut_build_ASAN test/CMakeFiles/doris_be_test.dir/exprs/function/function_jsonb_test.cpp.o` - Format check: `build-support/clang-format.sh`; `build-support/check-format.sh`; `git diff --check` - Behavior changed: No - Does this need documentation: No
1 parent 6ac210b commit dc7b50c

2 files changed

Lines changed: 27 additions & 2 deletions

File tree

be/src/exprs/function/function_jsonb.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,6 +2048,7 @@ class FunctionJsonbModify : public IFunction {
20482048

20492049
bool replace = false;
20502050
parents.emplace_back(json_documents[row_idx]->getValue());
2051+
const auto legs_count = json_path[path_index].get_leg_vector_size();
20512052
if (find_result.value) {
20522053
// find target path, replace it with the new value.
20532054
replace = true;
@@ -2058,7 +2059,8 @@ class FunctionJsonbModify : public IFunction {
20582059
} else {
20592060
// does not find target path, insert the new value.
20602061
JsonbPath new_path;
2061-
for (size_t j = 0; j < json_path[path_index].get_leg_vector_size() - 1; ++j) {
2062+
DCHECK_GT(legs_count, 0);
2063+
for (size_t j = 0; j + 1 < legs_count; ++j) {
20622064
auto* current_leg = json_path[path_index].get_leg_from_leg_vector(j);
20632065
std::unique_ptr<leg_info> leg = std::make_unique<leg_info>(
20642066
current_leg->leg_ptr, current_leg->leg_len,
@@ -2072,7 +2074,6 @@ class FunctionJsonbModify : public IFunction {
20722074
}
20732075
}
20742076

2075-
const auto legs_count = json_path[path_index].get_leg_vector_size();
20762077
leg_info* last_leg =
20772078
legs_count > 0
20782079
? json_path[path_index].get_leg_from_leg_vector(legs_count - 1)

be/test/exprs/function/function_jsonb_test.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,4 +986,28 @@ TEST(FunctionJsonbTEST, JsonContains) {
986986
ASSERT_TRUE(st.ok()) << "execute failed: " << st.to_string();
987987
}
988988

989+
TEST(FunctionJsonbTEST, JsonbModifyMissingPathParent) {
990+
InputTypeSet input_types = {PrimitiveType::TYPE_JSONB, PrimitiveType::TYPE_VARCHAR,
991+
PrimitiveType::TYPE_JSONB};
992+
993+
{
994+
DataSet data_set = {
995+
{{STRING("{}"), STRING("$.a"), STRING("1")}, STRING(R"({"a":1})")},
996+
{{STRING(R"({"a":{}})"), STRING("$.a.b"), STRING("2")}, STRING(R"({"a":{"b":2}})")},
997+
{{STRING(R"({"a":[1]})"), STRING("$.a[1]"), STRING("2")}, STRING(R"({"a":[1,2]})")},
998+
};
999+
static_cast<void>(
1000+
check_function<DataTypeJsonb, true>("jsonb_insert", input_types, data_set));
1001+
}
1002+
1003+
{
1004+
DataSet data_set = {
1005+
{{STRING("{}"), STRING("$.a"), STRING("1")}, STRING(R"({"a":1})")},
1006+
{{STRING(R"({"a":{}})"), STRING("$.a.b"), STRING("2")}, STRING(R"({"a":{"b":2}})")},
1007+
{{STRING(R"({"a":[1]})"), STRING("$.a[1]"), STRING("2")}, STRING(R"({"a":[1,2]})")},
1008+
};
1009+
static_cast<void>(check_function<DataTypeJsonb, true>("jsonb_set", input_types, data_set));
1010+
}
1011+
}
1012+
9891013
} // namespace doris

0 commit comments

Comments
 (0)