Lezen in het Engels

Delen via


C++ class data members not getting correctly initialized due to unbalanced #pragma pack alignment

Sometime back we saw an odd behavior in which C++ class data members were not getting correctly initialized due to memory corruption. It was discovered that this memory corruption was due to an unbalanced #pragma pack data alignment. In our case, this behavior was observed right after the constructor of the class was executed. To troubleshoot this issue, the next thing was to dump the class in WinDBG using the command dt. This would show a layout similar to below:

 

0:000> dt CFoo 0x02309ce4 -r2

MyClass!CFoo

   +0x000 __VFN_table : 0x009f5c48

   =00abc44c CFoo::LOG: 0x009f5bfc "Log"

…[Snip]

+0x0b9 _frmtFoo: std::vector<CFrmtFoo*,std::allocator< CFrmtFoo *> >

      +0x000 _Myfirstiter : 0x0012fa7c std::_Iterator_base

         +0x000 _Mycont : 0x02309d9d std::_Container_base

         +0x004 _Mynextiter : 0x00cdcdcd std::_Iterator_base

      +0x004 _Alval : std::allocator< CFrmtFoo *>

      +0x008 _Myfirst : 0x00cdcdcd -> 0x0462cb02 CFrmtFoo

         +0x000 __VFN_table : ????

Carefully observe the offset 0x0b9 highlighted in red. For a C++ class these offsets represent a value where the data members are aligned. These values are affected by the use of #pragma pack( [n] ) directive. When you use #pragma pack( [n] ) , where n is 1, 2, 4, 8, or 16, each member after the first is stored on the smaller member type or n-byte boundaries. In our case it’s an odd value. It was soon discovered that the application was using custom packing i.e. packing own classes, structures using #pragma pack or using /Zp. The application was changing the data packing alignment other than the default value 8. Now this application internally made use of third partly library which was designed to use data alignment pack level 8. Because of this unbalanced packing alignment the members were getting incorrectly initialized and thus resulting in memory corruption. A small tweak in the code made this work.

 

#pragma pack(push, 8)

#include <ThirdParty.h> // Third Party component library which expects 8 bit packing alignment

#pragma pack(pop)

Note, if you use pop and specify a value for n, that value becomes the new packing value. So in above code snippet if you specify the last statement as #pragma pack(pop, 8), 8 would be the new packing value and not the one which you set previously for your application. So be carefully when you use pop,itmay unbalance the stack!