Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TClass and ROOT I/O mistreat bit-field members #17501

Open
hahnjo opened this issue Jan 23, 2025 · 0 comments
Open

TClass and ROOT I/O mistreat bit-field members #17501

hahnjo opened this issue Jan 23, 2025 · 0 comments

Comments

@hahnjo
Copy link
Member

hahnjo commented Jan 23, 2025

Description

TClass / TDataMember do not carry enough information for bit-field members: The offset is the rounded-down byte offset, while the type is the underlying one. This leads to wrong behavior during I/O, so we should at least warn the user.

Reproducer

#include <TMemFile.h>
#include <TTree.h>

#include <ROOT/RNTupleModel.hxx>
#include <ROOT/RNTupleReader.hxx>
#include <ROOT/RNTupleWriter.hxx>

using ROOT::Experimental::RNTupleModel;
using ROOT::Experimental::RNTupleReader;
using ROOT::Experimental::RNTupleWriter;

#include <iostream>

struct BitField {
  int a : 16;
  int b : 16;
  int c; //!

  void Print() const {
    std::cout << "a = " << a << ", b = " << b << ", c = " << std::hex << c << "\n";
  }
};

void test_BitField() {
  TMemFile f("mem.root", "RECREATE");

  {
    std::cout << "Writing:\n";
    BitField obj{1, 2, 0x44444444};
    obj.Print();

    f.WriteObject(&obj, "obj");

    TTree tree;
    tree.Branch("obj", &obj);
    tree.Fill();
    f.WriteObject(&tree, "tree");

    auto model = RNTupleModel::Create();
    auto objPtr = model->MakeField<BitField>("obj");
    auto writer = RNTupleWriter::Append(std::move(model), "ntpl", f);
    *objPtr = obj;
    writer->Fill();
  }
  std::cout << "\n";

  {
    std::cout << "Reading:\n";
    BitField *objPtr = new BitField{0, 0, 0x55555555};
    objPtr->Print();
    std::cout << "(TDirectory::GetObject reallocates without freeing...)\n";
    f.GetObject("obj", objPtr);
    objPtr->Print();
    delete objPtr;
    std::cout << "\n";

    TTree *treePtr = nullptr;
    f.GetObject("tree", treePtr);
    objPtr = new BitField{0, 0, 0x55555555};
    objPtr->Print();
    treePtr->SetBranchAddress("obj", &objPtr);
    treePtr->GetEntry(0);
    objPtr->Print();
    delete objPtr;
    delete treePtr;
    std::cout << "\n";

    std::unique_ptr<ROOT::RNTuple> ntpl(f.Get<ROOT::RNTuple>("ntpl"));
    auto reader = RNTupleReader::Open(*ntpl);
    objPtr = reader->GetModel().GetDefaultEntry().GetPtr<BitField>("obj").get();
    *objPtr = BitField{0, 0, 0x55555555};
    objPtr->Print();
    reader->LoadEntry(0);
    objPtr->Print();
  }
}

Output:

Writing:
a = 1, b = 2, c = 44444444

Reading:
a = 0, b = 0, c = 55555555
(TDirectory::GetObject reallocates without freeing...)
a = 1, b = 2, c = 4444

a = 0, b = 0, c = 55555555
a = 1, b = 2, c = 55554444

a = 0, b = 0, c = 55555555
a = 1, b = 2, c = 55554444
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants