Opened 14 years ago
Closed 14 years ago
#1946 closed Bugs (fixed)
[type_traits] type_with_alignment fails on non-power-of-2 alignment
Reported by: | Owned by: | John Maddock | |
---|---|---|---|
Milestone: | Boost 1.36.0 | Component: | type_traits |
Version: | Boost 1.35.0 | Severity: | Problem |
Keywords: | type_traits alignment | Cc: |
Description
The type_with_alignment template fails to compile if the alignment is not a power of 2. This is a possible situation at least with MSVC 9.0. The following class of a user-defined stream gets alignment of 12:
class my_stream :
public std::ostream
{ public:
typedef boost::function0< void > function_type; function_type m_function;
};
I've attached a reduced code sample with more comments and the compiler error message.
I suggest to add a fallback type_with_alignment type in case if the alignment is not a power of 2. This type should have the requested alignment. It may be achieved with the declspec(align(n)) specifier.
Attachments (1)
Change History (3)
by , 14 years ago
Attachment: | tt_failure.cpp added |
---|
comment:1 by , 14 years ago
Status: | new → assigned |
---|
This is really strange and appears to be an MSVC bug:
The true alignment of the type as reported by alignof is 8, but The size of the type as reported by sizeof is 44, so...
If you declare an array of my_class then some of the objects will *not* be 8-byte aligned, because the objects size is not a multiple of it's alignment!
Even stranger, when my_class is placed in boost::detail::alignment_of_hack (the class we use to calculate the alignment), then it is placed on a 8-byte alignment, and alignment_of_hack gets given some trailing padding to pack out the class to a multiple of 8 (it needs this because sizeof(my_class) isn't a multiple of 8).
So sometimes MSVC does the wrong thing, and sometimes it corrects itself, either way it really confuses our internal logic.
I'm not really sure what to do here, except perhaps to start using the align_of intrinsic... I'll look into that.
Regards, John.
PS I used the code below to deduce the above:
#include <boost/function.hpp> #include <boost/type_traits/alignment_of.hpp> #include <boost/type_traits/type_with_alignment.hpp>
#ifdef _MSC_VER This kind of packing is set within MSVC 9.0 headers. E.g. std::ostream has it. #pragma pack(push,8) #endif /* _MSC_VER */
The issue is gone if Root has no data members struct Root { int a; }; The issue is gone if Root is inherited non-virtually struct A : virtual public Root {};
#ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */
The class gets alignment 12 for some reason The real-world case that triggered the problem is a user-defined stream class that derived from std::ostream. Such class could not be used with tools involving type_with_alignment. class my_class :
public A
{ public:
The issue is gone if the type is not a boost::function. The signature doesn't matter. typedef boost::function0< void > function_type; function_type m_function;
};
struct alignment_of_hack {
char c; my_class t;
};
int main(int, char*[]) {
/*
boost::type_with_alignment<
boost::alignment_of<
my_class
::value ::type obj;
return static_cast< int >(&obj != NULL); */
std::cout << "True alignment of my_class is: " << alignof(my_class) << std::endl; std::cout << "Size of my_class is: " << sizeof(my_class) << std::endl;
alignment_of_hack h;
std::cout << "Size of alignment_hack is: " << sizeof(h) << std::endl; std::cout << "Offset of my_class in alignment_hack is: " << (reinterpret_cast<char*>(&(h.t)) - reinterpret_cast<char*>(&h)) << std::endl;
my_class a[10];
for(int i = 0; i < 10; ++i) {
int location = (reinterpret_cast<char*>(&(a[i])) - reinterpret_cast<char*>(a)); std::cout << location << " " << (location % alignof(my_class)) << std::endl;
}
return 0;
}
comment:2 by , 14 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
The sample code that reproduces the problem