From 6dac87d0ede35a3dd9685f5894512ff560a049e9 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 0917432397507..7fcef29575a64 100644 --- a/tree/ntuple/src/RFieldSequenceContainer.cxx +++ b/tree/ntuple/src/RFieldSequenceContainer.cxx @@ -264,10 +264,7 @@ unsigned char *ROOT::RRVecField::ResizeRVec(void *rvec, std::size_t nItems, std: } // 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 = static_cast(malloc(nItems * itemSize)); diff --git a/tree/ntuple/test/rfield_vector.cxx b/tree/ntuple/test/rfield_vector.cxx index 0e505cbd7e5ad..dbf4526fc0133 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");