Opened 7 years ago
Closed 7 years ago
#11309 closed Bugs (fixed)
is_virtual_base_of has false positives caused by sizeof alignment
Reported by: | Owned by: | John Maddock | |
---|---|---|---|
Milestone: | To Be Determined | Component: | type_traits |
Version: | Boost 1.57.0 | Severity: | Problem |
Keywords: | Cc: |
Description
The is_virtual_base_of type<Base, Derived> type trait can report virtual bases in situations when there isn't any. Here's an example code snippet where it fails:
#include <iomanip> #include <iostream> #include <boost/type_traits.hpp> struct A { int a; }; struct B : public virtual A {}; struct C : public A { virtual ~C() {} }; int main() { std::cout << std::boolalpha; std::cout << "Is A a virtual base of B? " << boost::is_virtual_base_of<A, B>::value << std::endl; std::cout << "Is A a virtual base of C? " << boost::is_virtual_base_of<A, C>::value << std::endl; return 0; }
In the above code both checks are true despite A being a non-virtual base of C. The reason for this is that alignment is affecting the results from sizeof and it’s making two different sizes seem equal.
In particular:
sizeof(is_virtual_base_of_impl<A, C, mpl::true_>::boost_type_traits_internal_struct_X) == 16 sizeof(is_virtual_base_of_impl<A, C, mpl::true_>::boost_type_traits_internal_struct_Y) == 16
However, if we redefine C as packed (example for gcc / clang):
struct C : public A { virtual ~C() {} } __attribute__((packed);
Then the sizes do mismatch as expected and the result is correct:
sizeof(is_virtual_base_of_impl<A, C, mpl::true_>::boost_type_traits_internal_struct_X) == 16 sizeof(is_virtual_base_of_impl<A, C, mpl::true_>::boost_type_traits_internal_struct_Y) == 12
The solution for this problem would be to define the auxiliary types boost_type_traits_internal_struct_X and boost_type_traits_internal_struct_Y as packed in such a way that works across all supported compilers. This might be some combination of _ _attribute_ _((packed)) for gcc/clang, #pragma pack for the Visual C++ compiler and others.
Attributes didn't help, but this seems to get it: https://github.com/boostorg/type_traits/commit/24b7d226d3316d36711c40b7ca854c2b2d4565be