1

I had some code that works at the low level that used to work with glm. I switched all uses of glm to Eigen And I am now observing a strange behaviour where the same struct seems to have different alignments at different points in the code.

This is what gdb gives me after initializtion:

(gdb) p sizeof(CellShadingInfo)
$1 = 240
(gdb) 

Now let's see the construction of a specific global structure:

const std::unordered_map<std::string, size_t> uniform_size_map = {
    {"GuiTransform", sizeof(GuiTransform)},
    {"UniformBufferObject", sizeof(UniformBufferObject)},
    {"GuiVisualProperties", sizeof(GuiVisualProperties)},
    {"PostProcessingEffects", sizeof(PostProcessingEffects)},
    {"LineProperties", sizeof(LineProperties)},
    {"PointInfo", sizeof(PointInfo)},
    {"GaussianVisualization", sizeof(GaussianVisualization)},
    {"ParticleUBO", sizeof(ParticleUBO)},
    {"CameraInfo", sizeof(CameraInfo)},
    {"MVPOnlyUbo", sizeof(MVPOnlyUbo)},
    {"WireframeDebugInfo", sizeof(WireframeDebugInfo)},
    {"CellShadingInfo", sizeof(CellShadingInfo)},
    {"GaussianProperties", sizeof(GaussianProperties)}
};

That's global, so the initialization code for this would run before main. But as the LUP has been defined to be constant, all values in there should be final, thus preventing accidental overwrites.

However according to gdb:

(gdb) p uniform_size_map 
$2 = std::unordered_map with 13 elements = {["CellShadingInfo"] = 228, ["MVPOnlyUbo"] = 192, ["ParticleUBO"] = 16, 
  ["GaussianVisualization"] = 48, ["PointInfo"] = 36, ["PostProcessingEffects"] = 8, ["GuiVisualProperties"] = 20, 
  ["GaussianProperties"] = 8, ["CameraInfo"] = 12, ["UniformBufferObject"] = 192, ["WireframeDebugInfo"] = 16, 
  ["LineProperties"] = 40, ["GuiTransform"] = 16}

So the only explanation I have is that the compiler used a different alignment during compilation of preinit methods vs regular runtime. That however sounds ridiculous.

Makogan
  • 8,208
  • 7
  • 44
  • 112
  • My guess would be, you have several different definitions of `CellShadingInfo`, either in different namespaces (that's OK), or in the same namespace but in different translation units (that's ODR violation). Perhaps there are members that are included or excluded, or change type, based on a macro; and different translation units are compiled with different macros defined. – Igor Tandetnik Aug 03 '20 at 01:26
  • There is a single declaration of CellShadingInfo in the entire program (just checked with grep), the only use of the macroprocessor I am using is through includes. Can this cause the issue? – Makogan Aug 03 '20 at 01:36
  • Well, it could be something like `struct CellShadingInfo {SomeType x;}` where the definition of `SomeType` varies between translation units. Or there could be an array with a bound defined by a constant that varies. There are many ways in which ODR violation could creep in. – Igor Tandetnik Aug 03 '20 at 01:37
  • "where the definition of SomeType varies between translation units" I am 100% sure this happens with Eigen vectors. That structure has plenty of them but everything else is just plain ints and floats, so that's what the problem must be. How can I fix it? – Makogan Aug 03 '20 at 01:41
  • Figure out why they end up being different, ensure you have consistent build configuration across all your translation units. – Igor Tandetnik Aug 03 '20 at 01:42
  • Is it possible to force a specific size through preprocessor commands? – Makogan Aug 03 '20 at 01:48
  • You can't force an arbitrary structure to have an arbitrary size, if that's what you are asking. I suppose I don't understand the question. – Igor Tandetnik Aug 03 '20 at 01:50
  • In this case, Eigen::Vector refers specifically to vectors of size 2,3 and 4, whose sizes are known at compile time (a priori). Thus in theory it should be possible to determine a unique size for the structure at compile time. – Makogan Aug 03 '20 at 01:52
  • Well, normally, a structure does have a fixed size known at compile time. Most programs don't contain ODR violations. – Igor Tandetnik Aug 03 '20 at 01:54
  • You can add `static_assert(sizeof(MyType) == /* expected size */);` (or `alignof(MyType)`). If it fails to compile, you know that the size/alignment is incorrect at some location. – Justin Aug 03 '20 at 02:16
  • The simple answer to this question is "no". If a C++ struct has different alignment requirements at different points in the program, then there is either a diagnosable error (e.g. compiler has visibility of both definitions in one compilation unit) or undefined behaviour (e.g. different definitions of the same struct in different compilation units). Programmers need to ensure such things don't happen. – Peter Aug 03 '20 at 02:35
  • Found the problem, an object file was not getting recompiled for some reason. So my program was using 2 different versions of teh same struct depending on which file was getting linked. (A new one with the current alignment or an old one with the old) – Makogan Aug 03 '20 at 03:33

1 Answers1

0

The issue was a compilation problem. For unknown reasons an object file was failing to compile, as a result the linker was finding the old object file and linking against that. Since that object file was made from old source code, the structure didn't have the same alignment anymore in different sections of the code.

Makogan
  • 8,208
  • 7
  • 44
  • 112