Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions io/io/src/TFileMerger.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,13 @@ Bool_t TFileMerger::MergeOne(TDirectory *target, TList *sourcelist, Int_t type,
}
// Check if only the listed objects are to be merged
if (type & kOnlyListed) {
oldkeyname = keyname;
oldkeyname += " ";
onlyListed = fObjectNames.Contains(oldkeyname);
oldkeyname = keyname;
// Search for " key " in " a b c " to match whole words only.
// Without the leading space, a key that is a prefix or suffix of a listed name
// would match. AddObjectNames() guarantees a trailing space in fObjectNames.
TString searchName = " ";
searchName += keyname;
searchName += " ";
onlyListed = (" " + fObjectNames).Contains(searchName);
if ((!onlyListed) && (!cl->InheritsFrom(TDirectory::Class()))) return kTRUE;
}

Expand Down
38 changes: 38 additions & 0 deletions io/io/test/TFileMergerTests.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,44 @@ TEST(TFileMerger, MergeSingleOnlyListed)
EXPECT_EQ(output->GetListOfKeys()->GetSize(), 2);
}

TEST(TFileMerger, OnlyListedNoSuffixLeak)
{
// Regression test for https://github.com/root-project/root/issues/22414:
// keys whose names are a prefix or suffix of a listed key must not appear in the output.
TMemFile src("OnlyListedNoSuffixLeakSrc.root", "CREATE");

// "short" is a suffix of "long_short"; "long" is a prefix — both must be excluded.
auto hLongShort = new TH1F("long_short", "long_short", 1, 0, 2);
auto hShort = new TH1F("short", "short", 1, 0, 2);
auto hLong = new TH1F("long", "long", 1, 0, 2);
auto hUnrelated = new TH1F("unrelated", "unrelated", 1, 0, 2);
for (auto h : {hLongShort, hShort, hLong, hUnrelated})
h->SetDirectory(&src);
src.Write();

TFileMerger merger;
auto output = std::unique_ptr<TFile>(new TFile("OnlyListedNoSuffixLeak.root", "RECREATE"));
Comment thread
guitargeek marked this conversation as resolved.
ASSERT_TRUE(merger.OutputFile(std::move(output)));

merger.AddObjectNames("long_short"); // only this one should appear in output
merger.AddFile(&src, false);

const Int_t mode = TFileMerger::kAll | TFileMerger::kRegular | TFileMerger::kOnlyListed;
ASSERT_TRUE(merger.PartialMerge(mode));

output = std::unique_ptr<TFile>(TFile::Open("OnlyListedNoSuffixLeak.root"));
ASSERT_TRUE(output.get() && output->GetListOfKeys());

// Exactly one key: "long_short". Suffix, prefix, and unrelated keys must be absent.
EXPECT_EQ(output->GetListOfKeys()->GetSize(), 1);
EXPECT_NE(output->Get("long_short"), nullptr);
EXPECT_EQ(output->Get("short"), nullptr);
EXPECT_EQ(output->Get("long"), nullptr);
EXPECT_EQ(output->Get("unrelated"), nullptr);
output->Close();
gSystem->Unlink("OnlyListedNoSuffixLeak.root");
}

// https://github.com/root-project/root/issues/14558 aka https://its.cern.ch/jira/browse/ROOT-4716
TEST(TFileMerger, MergeBranches)
{
Expand Down
Loading