You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[ntuple] Bad state after attempting to make field for virtual type #13910
If a code attempts to create a field in an RNTuple for a virtual object type, it rightfully fails, but not with a very clear warning as to why (as compared to constructing the object on the interpreter). However, after the failure, types that should be OK to make fields from now fail. So I guess some internal data structure gets corrupted.
Reproducer
importROOTROOT.gInterpreter.Declare("""\class Abstract { public: Abstract() : data1_(3) {}; virtual ~Abstract() {}; virtual int method() = 0; private: int data1_;};class Derived : public Abstract { public: Derived() : Abstract() {}; int method() override { return data2_; }; private: int data2_;};""")
model=ROOT.Experimental.RNTupleModel.Create()
# Derived can be constructed without complaint# obj1 = model.MakeField["Derived"]("test1")# If we attempt (foolishly) to make Abstract, and# catch the exception, then later attempts to make Derived now fail# with puzzling JIT errorstry:
obj1=model.MakeField["Abstract"]("test1")
exceptValueErrorasex:
print(ex)
obj2=model.MakeField["Derived"]("test2")
changed the title [-][rntuple] Bad state after attempting to make field for virtual type[/-][+][ntuple] Bad state after attempting to make field for virtual type[/+]on Oct 20, 2023
After a quick look, this appears to a be a DeclUnloader problem because of the failed transaction. On the C++ prompt, both cases (abstract class and class without default constructor) work, only some warnings (again related to DeclUnloader)...
I reproduced this on 6.40.04 and traced the remaining failure to RNTuple.
On 6.40.04 the later cascading JIT failure no longer reproduces, and the original Python repro no longer triggers because PyROOT creates bare models: MakeField does not construct a value. ROOT.Experimental.RNTupleModel is now ROOT.RNTupleModel.
In C++ with a default entry (RNTupleModel::Create()), MakeField<Abstract>() (or a class without a default constructor) makes TClass::New() JIT an invalid constructor wrapper. RClassField::ConstructValue() ignored the null return, so MakeField returned a non-null shared_ptr to unconstructed memory; destroying it segfaults in RClassDeleter.
The failed TClass::New compilation is the Cling transaction trigger from this issue.
I opened #23806 with a fix: pre-check kIsAbstract/HasDefaultConstructor(kTRUE) before TClass::New, throw RException, free the buffer on failure, and make REntry::AddValue exception-safe. It includes a roottest regression. I validated it against 6.40.04 via a preload shim + ACLiC (pre-patch: bad pointer/crash; post-patch: clean exception and model still usable); no full rebuild here, so CI will be the first full-build run.
For PyROOT users on current releases, a practical guard before MakeField is:
Activity
nsmith- commentedon Oct 20, 2023
The same symptom also appears if I try to make a field for a class with no default constructor:
There, I even get
which is very weird, why would we be making the symbol
[-][rntuple] Bad state after attempting to make field for virtual type[/-][+][ntuple] Bad state after attempting to make field for virtual type[/+]hahnjo commentedon Feb 14, 2024
After a quick look, this appears to a be a
DeclUnloaderproblem because of the failed transaction. On the C++ prompt, both cases (abstract class and class without default constructor) work, only some warnings (again related toDeclUnloader)...ferdymercury commentedon Aug 6, 2025
I tried both code snippets in ROOT master (debug build) and I do not see any crash, but there is no warning issued either.
SamdaniSayam commentedon Oct 23, 2026
I reproduced this on 6.40.04 and traced the remaining failure to RNTuple.
MakeFielddoes not construct a value.ROOT.Experimental.RNTupleModelis nowROOT.RNTupleModel.RNTupleModel::Create()),MakeField<Abstract>()(or a class without a default constructor) makesTClass::New()JIT an invalid constructor wrapper.RClassField::ConstructValue()ignored the null return, soMakeFieldreturned a non-nullshared_ptrto unconstructed memory; destroying it segfaults inRClassDeleter.TClass::Newcompilation is the Cling transaction trigger from this issue.I opened #23806 with a fix: pre-check
kIsAbstract/HasDefaultConstructor(kTRUE)beforeTClass::New, throwRException, free the buffer on failure, and makeREntry::AddValueexception-safe. It includes a roottest regression. I validated it against 6.40.04 via a preload shim + ACLiC (pre-patch: bad pointer/crash; post-patch: clean exception and model still usable); no full rebuild here, so CI will be the first full-build run.For PyROOT users on current releases, a practical guard before
MakeFieldis:(
0x40iskIsAbstract, not exposed in Python.) For closed polymorphism,std::variant<ConcreteA, ConcreteB>is the supported RNTuple representation.