Genreflex and debug builds

Dear All,

I’m trying to understand genreflex's behaviour, but had to realise that I understand it much less than I thought… I observed a very nasty issue in our code today that I was trying to reproduce in a standalone way, but couldn’t.

The issue is with one class that is something like this:

class TrickyClass {
   ...
private:
#ifndef NDEBUG
   bool m_isInitialized = false;
#endif // not NDEBUG
   ...
};

The idea being that we would only use the m_isInitialized member in debug builds. So the cxx of the class also has a few #ifndef statements in it.

What I observed in our “full build” was that in a debug build I would get nasty runtime errors/crashes. Investigating this with Valgrind I found that the problem was that we create objects of this type (actually objects holding members of this type…) through its dictionary. And the dictionary doesn’t allocate memory of the right amount for this class in debug mode.

So I was trying to reproduce this issue with a simple example. But I’m just not able to. What I find is that for the class that I observed this on originally, the generated dictionary would only have these functions defined:

...
namespace ROOT {
   static TClass *CPcLcLEgammaCalibrationAndSmearingAlg_Dictionary();
   static void CPcLcLEgammaCalibrationAndSmearingAlg_TClassManip(TClass*);
   static void delete_CPcLcLEgammaCalibrationAndSmearingAlg(void *p);
   static void deleteArray_CPcLcLEgammaCalibrationAndSmearingAlg(void *p);
   static void destruct_CPcLcLEgammaCalibrationAndSmearingAlg(void *p);
...

While in my “simple example” I would always get some additional functions as well.

...
namespace ROOT {
   static TClass *MyClass_Dictionary();
   static void MyClass_TClassManip(TClass*);
   static void *new_MyClass(void *p = 0);
   static void *newArray_MyClass(Long_t size, void *p);
   static void delete_MyClass(void *p);
   static void deleteArray_MyClass(void *p);
   static void destruct_MyClass(void *p);
...

What would be the reason for this? Why does the dictionary for the CP::EgammaCalibrationAndSmearingAlg type not have new_ functions? It’s not an abstract type. ROOT is able to construct such objects through their dictionaries.

In any case, I suspect that I see the problem in our full build because of this. That the way that the dictionary allocates a new instance of this algorithm is different than how I try to allocate an instance of my test class in the standalone example.

For now we’ll just give up on using NDEBUG in the header of this class, but I’d still very much like to understand what is going wrong.

Cheers,
Attila

P.S. And yes, I did check that the NDEBUG flag is not provided to the genreflex call in our full build in debug mode.

Could this be connected to https://github.com/root-project/root/commit/cd7ecf5ee0f18e93287be3489819dd75a68770f8 ?

And in general it’s a fairly terrible idea to change class layout based on DEBUG / NDEBUG: you cannot control all your “clients” to build their own libraries in the same “use debug or not” setting as “your” library. At least for ROOT we avoid it at all costs.

Hi Axel,

No arguments here. We’re removing this from our code now.

What you point to does seem like it would be the thing responsible for what I’ve seen. But I didn’t manage to reproduce this behaviour in a lightweight example even when using exactly the same ROOT installation as our full build is using.

The only difference I could see in the generated dictionaries was what I’ve shown here. That in our “full build” no new_ functions got generated for the problematic classes for some reason.

Still, I guess we’re okay with just solving the problem on our end.

Cheers,
Attila

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