From 641524be0a3c4920aa157913e2f69f7169d93f62 Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Mon, 20 Jul 2026 11:09:31 +0200 Subject: [PATCH] [ntuple] fix RVec resize from small to large vector Resizing needs to check if the previous buffer pointed to the small vector space before releasing the memory. (cherry picked from commit 9f4a1ea79f9858f8b5066300fb7b595c67dd49d5) --- tree/ntuple/src/RFieldSequenceContainer.cxx | 5 +--- tree/ntuple/test/rfield_vector.cxx | 33 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/tree/ntuple/src/RFieldSequenceContainer.cxx b/tree/ntuple/src/RFieldSequenceContainer.cxx index 4d02594088618..1f54434adb162 100644 --- a/tree/ntuple/src/RFieldSequenceContainer.cxx +++ b/tree/ntuple/src/RFieldSequenceContainer.cxx @@ -287,10 +287,7 @@ void ROOT::RRVecField::ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) } // TODO Increment capacity by a factor rather than just enough to fit the elements. - if (owns) { - // *beginPtr points to the array of item values (allocated in an earlier call by the following malloc()) - free(*beginPtr); - } + Internal::DestroyRVecWithChecks(itemField->GetAlignment(), beginPtr, capacityPtr); // We trust that malloc returns a buffer with large enough alignment. // This might not be the case if T in RVec is over-aligned. *beginPtr = malloc(nItems * fItemSize); diff --git a/tree/ntuple/test/rfield_vector.cxx b/tree/ntuple/test/rfield_vector.cxx index 1f4f858d36877..dc6eb72d1c079 100644 --- a/tree/ntuple/test/rfield_vector.cxx +++ b/tree/ntuple/test/rfield_vector.cxx @@ -203,6 +203,39 @@ TEST(RNTuple, RVec) EXPECT_EQ(1.0, (*rdJetsAsStdVector)[0]); } +TEST(RNTuple, RVecResizeSmall) +{ + FileRaii fileGuard("test_ntuple_rvec_small.root"); + + constexpr int N = 260; // more elements than fit in any small vector storage + + { + auto model = RNTupleModel::Create(); + auto v = model->MakeField>("v"); + for (int i = 0; i < N; ++i) { + v->push_back(i); + } + + auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); + writer->Fill(); + } + + auto reader = RNTupleReader::Open("ntpl", fileGuard.GetPath()); + EXPECT_EQ(1U, reader->GetNEntries()); + + ROOT::RVec v; + EXPECT_TRUE(ROOT::Detail::VecOps::IsSmall(v)); + auto e = reader->CreateEntry(); + e->BindRawPtr("v", &v); + + reader->LoadEntry(0, *e); + ASSERT_EQ(v.size(), N); + EXPECT_FALSE(ROOT::Detail::VecOps::IsSmall(v)); + for (int i = 0; i < N; ++i) { + EXPECT_EQ(i, v[i]); + } +} + TEST(RNTuple, RVecTypeErased) { FileRaii fileGuard("test_ntuple_rvec_typeerased.root");