Skip to content

Commit dd0823e

Browse files
committed
Harden merging of VLAs
Protect against GetMaximum() not returning the correct number and for the case all the VLAs are empty. Validate number of entries if fast cloning is used.
1 parent 85ac260 commit dd0823e

1 file changed

Lines changed: 43 additions & 2 deletions

File tree

Framework/AODMerger/src/aodMerger.cxx

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,21 @@ int main(int argc, char* argv[])
286286
}
287287
outputDir->cd();
288288
auto outputTree = inputTree->CloneTree(-1, (fastCopy) ? "fast" : "");
289+
// Validate that all branches have the same number of entries after CloneTree.
290+
// Fast copy from remote (xrootd) sources can silently produce corrupt trees
291+
// if a read fails mid-transfer.
292+
{
293+
auto expectedEntries = outputTree->GetEntries();
294+
TObjArray* clonedBranches = outputTree->GetListOfBranches();
295+
for (int ib = 0; ib < clonedBranches->GetEntriesFast(); ++ib) {
296+
auto* br = (TBranch*)clonedBranches->UncheckedAt(ib);
297+
if (br->GetEntries() != expectedEntries) {
298+
printf(" *** FATAL ***: After CloneTree, branch %s has %lld entries but tree has %lld\n",
299+
br->GetName(), br->GetEntries(), expectedEntries);
300+
exitCode = 7;
301+
}
302+
}
303+
}
289304
currentDirSize += inputTree->GetTotBytes(); // NOTE outputTree->GetTotBytes() is 0, so we use the inputTree here
290305
alreadyCopied = true;
291306
outputTree->SetAutoFlush(0);
@@ -307,7 +322,30 @@ int main(int argc, char* argv[])
307322

308323
// detect VLA
309324
if (((TLeaf*)br->GetListOfLeaves()->First())->GetLeafCount() != nullptr) {
310-
int maximum = ((TLeaf*)br->GetListOfLeaves()->First())->GetLeafCount()->GetMaximum();
325+
auto* sizeLeaf = ((TLeaf*)br->GetListOfLeaves()->First())->GetLeafCount();
326+
// GetMaximum() can be unreliable (may return 0 or a stale value).
327+
// Scan the size branch to find the true maximum.
328+
int maximum = sizeLeaf->GetMaximum();
329+
auto* sizeBranch = sizeLeaf->GetBranch();
330+
if (sizeBranch) {
331+
for (Long64_t e = 0, n = sizeBranch->GetEntries(); e < n; ++e) {
332+
sizeBranch->GetEntry(e);
333+
int val = sizeLeaf->GetValue();
334+
if (val > maximum) {
335+
printf(" *** WARNING ***: VLA size branch %s has a cached maximum %d which is smaller than the actual one (%d).",
336+
sizeLeaf->GetName(), maximum, val);
337+
maximum = val;
338+
}
339+
}
340+
}
341+
if (maximum < 0) {
342+
printf(" *** FATAL ***: VLA size branch %s has negative maximum %d\n", sizeLeaf->GetName(), maximum);
343+
exitCode = 6;
344+
break;
345+
}
346+
if (maximum == 0) {
347+
maximum = 1; // all entries are empty arrays, but we still need a valid buffer
348+
}
311349

312350
// get type
313351
static TClass* cls;
@@ -351,6 +389,9 @@ int main(int argc, char* argv[])
351389
}
352390
}
353391

392+
if (exitCode > 0) {
393+
break;
394+
}
354395
if (indexList.size() > 0) {
355396
auto entries = inputTree->GetEntries();
356397
int minIndexOffset = unassignedIndexOffset[treeName];
@@ -477,4 +518,4 @@ int main(int argc, char* argv[])
477518
printf("\n");
478519

479520
return exitCode;
480-
}
521+
}

0 commit comments

Comments
 (0)