SetBranchAddress strange behaviour or bug


ROOT Version: 6.14/00
Platform: ArchLinux x86_64
Compiler: GCC 8.1.1


Hi,

I’m having a very weird issue. Let’s look at the following code:

void foo() {
    auto tree = std::unique_ptr<TChain>(new TChain("DecayTree"));
    tree->AddFile("some_big_enough_file.root", 0);  // open and load file
    tree->GetEntry(0);  // make sure branch type checks work
    int test;
    if (tree->GetBranch("branch_may_not_exist")) {  // could be any check, but this shows my runtime usecase
        std::cout << "Should not print if branch does not exist\n";
        tree->SetBranchAddress("some_branch", &test);  // returns 0
    } else {
        tree->SetBranchAddress("some_other_branch", &test);  // returns 0
    }
    for (Long64_t i = 0; i < tree->GetEntries(); ++i) {
        tree->GetEntry(i);
        // none of the branches should contain values outside [-1, 0, 1]
        if (test >= 2 || test <= -2) std::cout << "test failed at entry " << i << std::endl;
    }
    return;
}

This is to process ROOT files depending on what branches are inside. In my opinion this test can only fail if there is a type mismatch, memory misalignment or some weird overflow. The test indeed fails if the file is big enough - in my case > ~16k entries.

Weirdly enough, after it fails for one entry, then it doesn’t fail again until ~45k and then succeeds again until ~60k and so on at ~80k, ~100k, …

The weird thing is, if I run this code however:

void foo() {
    auto tree = std::unique_ptr<TChain>(new TChain("DecayTree"));
    tree->AddFile("some_big_enough_file.root", 0);  // open and load file
    tree->GetEntry(0);  // make sure branch type checks work
    int test1, test2;
    if (tree->GetBranch("branch_may_not_exist")) {  // could be any check, but this shows my runtime usecase
        std::cout << "Should not print if branch does not exist\n";
        tree->SetBranchAddress("some_branch", &test1);  // returns 0
    } else {
        tree->SetBranchAddress("some_other_branch", &test2);  // returns 0
    }
    for (Long64_t i = 0; i < tree->GetEntries(); ++i) {
        tree->GetEntry(i);
        // none of the branches should contain values outside [-1, 0, 1]
        if (tree->GetBranch("branch_may_not_exist")) {
            if (test1 >= 2 || test1 <= -2) std::cout << "test failed at entry " << i << std::endl;
        else {
            if (test2 >= 2 || test2 <= -2) std::cout << "test failed at entry " << i << std::endl;
        }
    }
    return;
}

the test succeeds.

Is this intended behaviour or a bug?

EDIT: Actually, this must be a big. Second code snippet still had 1 failure in a million entries.

Thanks.

Try to “tree->Print();” and see what you get for the “some_branch” and the “some_other_branch”.

You may also try to execute “tree->SetMakeClass(1);” before you “SetBranchAddress”.

BTW. Before you return from your function, make sure you execute “tree->ResetBranchAddresses();”

I did do tree->Print() and everything looks fine. Also, if I open the branches in TBrowser the hist looks fine. The class check is done, I explicitly checked the return code of SetBranchAddress and the function here is an example, in reality this is a script to process a tuple and apply a cut. I realised my cut was failing and entries with incorrect values were being saved in the resulting file, then I made a minimal example once I identified the problem. But I’ll keep digging.

Try with an “analysis skeleton”:

I guess you have already checked that

  • your branches are really of type Int_t and not something different, for example they do not contain multiple leaves
  • No other branch is assigned to some (now) invalid memory location
  • The number of entries in the branch matches the number of entries in the tree
    Since you are calling tree->GetBranch("branch_may_not_exist") anyway, you could as well store the result and loop over this branch only and call br->GetEntry(i) / br->GetEntries() instead of tree->GetEntry(i) / tree->GetEntries().
  • What do you mean with “// make sure branch type checks work” - there is no type checking in SetBranchAddress, the second parameter is a void *.

Yes, I have confirmed that.

No

Checked it with PrintTree(), yes

Yes, I tried this now and did not work. But I initially wanted to avoid that altogether by using a single var

Currently running this check, so far no satisfactory results

If the TChain is not loaded fully, SetBranchAddress always returns kNoCheck, otherwise it calls CheckBranchAddressType() and in the case of my code returns kMatch. But sure, I might as well make a full call to SetBranchAddress and see if it changes anything. I doubt it, however, the types are the same, I’ve checked with TChain::PrintTree() and std::is_same<>::value

I will keep trying more things.

I was just saying kMatch does NOT ensure the type is correct - it isn’t checked. And I don’t understand how you can use std::is_same_v here - that’s a compile-time value!

This is what I meant:

root [1] std::is_same<Int_t, int>::value
(const bool) true
root [2] int test;
root [3] TClass testclass("testclass", kFALSE)
root [4] DecayTree->SetBranchAddress("B_OSKaonLatest_TAGDEC", &test, &testclass, EDataType::kInt_t, kTRUE)
(int) 0  // kMatch == 0

Another worrying thing is that TChain::MakeClass() succeeds,

root [7] DecayTree->MakeClass("class")
Info in <TTreePlayer::MakeClass>: Files: class.h and class.C generated from TTree: DecayTree
(int) 0

but TChain::MakeSelector() returns some badly sounding warnings.

root [8] DecayTree->MakeSelector("selector")
Warning in <AddReader>: Ingored branch B_ENDVERTEX_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch B_OWNPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch B_TOPPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch Jpsi_ENDVERTEX_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch Jpsi_OWNPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch Jpsi_TOPPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch Jpsi_ORIVX_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch muplus_OWNPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch muplus_TOPPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch muplus_ORIVX_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch muminus_OWNPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch muminus_TOPPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch muminus_ORIVX_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch X_ENDVERTEX_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch X_OWNPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch X_TOPPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch X_ORIVX_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch hplus_OWNPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch hplus_TOPPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch hplus_ORIVX_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch hminus_OWNPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch hminus_TOPPV_COV_ because type is unknown.
Warning in <AddReader>: Ingored branch hminus_ORIVX_COV_ because type is unknown.
(int) 0

TChain::MakeClass() identifies these correctly as:

...
Float_t         B_ENDVERTEX_COV_[3][3];
Float_t         B_TOPPV_COV_[3][3];
Float_t         Jpsi_ENDVERTEX_COV_[3][3];
...

So this seems to be a bug in 6.14/00. Running over the same file with 6.12/06 fixes the issue.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.

Can you provide a complete reproducer of the problem? Thanks.