Skip to content

Commit c737b0b

Browse files
committed
[io] Add type mismatch check for TObject-derived cases
Adds a check for type mismatch in TFileMerger for the particular case of having a TObject and trying to merge it against other objects of different types. Importantly, this includes also the check when the other object is of a non-TObject-derived type, which would previously lead to a segfault.
1 parent 6ab4902 commit c737b0b

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

io/io/src/TFileMerger.cxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,12 @@ Bool_t TFileMerger::MergeOne(TDirectory *target, TList *sourcelist, Int_t type,
661661
if (!hobj) {
662662
TKey *key2 = (TKey*)ndir->GetListOfKeys()->FindObject(keyname);
663663
if (key2) {
664+
if (strcmp(key2->GetClassName(), keyclassname) != 0) {
665+
Error("MergeRecursive", "Object type mismatch for key '%s' in file '%s': expected '%s' but found '%s'.",
666+
keyname, nextsource->GetName(), keyclassname, key2->GetClassName());
667+
nextsource = (TFile *)sourcelist->After(nextsource);
668+
return kFALSE;
669+
}
664670
hobj = key2->ReadObj();
665671
if (!hobj) {
666672
switch (fErrBehavior) {

io/io/test/TFileMergerTests.cxx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include "gtest/gtest.h"
2020

21+
#include <ROOT/TestSupport.hxx>
22+
2123
static void CreateATuple(TMemFile &file, const char *name, double value)
2224
{
2325
auto mytree = new TTree(name, "A tree");
@@ -396,3 +398,44 @@ TEST(TFileMerger, MergeSelectiveTutorial)
396398
EXPECT_NE(file.Get<TNtuple>("ntuple"), nullptr);
397399
}
398400
}
401+
402+
403+
TEST(TFileMerger, TypeMismatchErrorTObjectWithNonTObject)
404+
{
405+
struct PathRAII {
406+
std::string fPath;
407+
PathRAII(const char *path) : fPath(path) {}
408+
~PathRAII() { std::remove(fPath.c_str()); }
409+
};
410+
411+
PathRAII input1("ErrorIfTypeMismatch_input1.root");
412+
const auto objname{"myobj"};
413+
PathRAII input2("ErrorIfTypeMismatch_input2.root");
414+
PathRAII outputfile("ErrorIfTypeMismatch_output.root");
415+
416+
// Create two files with objects of different types, one must be a TObject-derived type and other a non-TObject-derived type
417+
{
418+
auto f = std::make_unique<TFile>(input1.fPath.c_str(), "RECREATE");
419+
auto t = std::make_unique<TTree>(objname, objname);
420+
f->Write();
421+
}
422+
423+
{
424+
auto f = std::make_unique<TFile>(input2.fPath.c_str(), "RECREATE");
425+
std::vector<int> v{1,2,3};
426+
f->WriteObject(&v, objname);
427+
}
428+
429+
// Ensure that TFileMerger detects the type mismatch and errors out.
430+
{
431+
ROOT::TestSupport::CheckDiagsRAII diagRAII;
432+
diagRAII.requiredDiag(kError, "TFileMerger::MergeRecursive", "expected 'TTree' but found 'vector<int>'", /*matchFullMessage*/false);
433+
diagRAII.requiredDiag(kError, "TFileMerger::Merge", "error during merge of your ROOT files");
434+
435+
TFileMerger fm;
436+
fm.OutputFile(outputfile.fPath.c_str());
437+
fm.AddFile(input1.fPath.c_str(), /*cpProgress*/ false);
438+
fm.AddFile(input2.fPath.c_str(), /*cpProgress*/ false);
439+
fm.PartialMerge();
440+
}
441+
}

0 commit comments

Comments
 (0)