Do not memset(0) POD types

"POD" is the wrong type trait to determine if something can be safely
zero-filled in order to achieve zero initialization. Consider a type
like

  struct POD { int POD::*ptr; };

This is a POD; its value initialization needs to value initialize the
member, and since it's a pointer, that's zero initialization, and that's
setting the pointer to null.

On Itanium, a null pointer to data member is not zero filled; it actually
has the value -1u.

Hence, zero-filling via memset(0) a POD object like the one above is
erroneous. Unfortunately there is no type trait in C++ that we can use to
know if a given datatype can be value initialized by zero-filling -- we
can check for trivial constructability, but that's a necessary
condition, not a sufficient one (POD above is also trivially
constructible).

The test is disabled on MSVC because of a compiler bug.

Fixes #238
This commit is contained in:
Giuseppe D'Angelo
2023-01-27 12:37:17 +01:00
parent acc5b088f5
commit b694ada294
3 changed files with 25 additions and 7 deletions

View File

@@ -1276,10 +1276,6 @@ member object and member function pointers) to be initializable using `std::mems
Most platforms are compatible with this initialization, but in case this initialization is not desired the Most platforms are compatible with this initialization, but in case this initialization is not desired the
user can `#define BOOST_CONTAINER_MEMZEROED_POINTER_IS_NOT_ZERO` before including library headers. user can `#define BOOST_CONTAINER_MEMZEROED_POINTER_IS_NOT_ZERO` before including library headers.
If neither `BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_NOT_ZERO` nor
`BOOST_CONTAINER_MEMZEROED_POINTER_IS_NOT_ZERO` is defined [*Boost.Container] also considers POD
types to be value initializable via `std::memset` with value zero.
[endsect] [endsect]
[endsect] [endsect]

View File

@@ -296,9 +296,6 @@ struct is_memzero_initializable
#if defined(BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_ZERO) #if defined(BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_ZERO)
|| dtl::is_floating_point<value_type>::value || dtl::is_floating_point<value_type>::value
#endif #endif
#if defined(BOOST_CONTAINER_MEMZEROED_FLOATING_POINT_IS_ZERO) && defined(BOOST_CONTAINER_MEMZEROED_POINTER_IS_NULL)
|| dtl::is_pod<value_type>::value
#endif
); );
}; };

View File

@@ -220,6 +220,12 @@ bool test_span_conversion()
#endif //BOOST_VECTOR_TEST_HAS_SPAN #endif //BOOST_VECTOR_TEST_HAS_SPAN
struct POD { int POD::*ptr; };
BOOST_STATIC_ASSERT_MSG
( boost::container::dtl::is_pod<POD>::value
, "POD test failed"
);
int main() int main()
{ {
{ {
@@ -392,5 +398,24 @@ int main()
); );
} }
////////////////////////////////////
// POD types should not be 0-filled testing
////////////////////////////////////
#if !defined(_MSC_VER)
// MSVC miscompiles value initialization of pointers to data members,
// https://developercommunity.visualstudio.com/t/Pointer-to-data-member-is-not-initialize/10238905
{
typedef boost::container::vector<POD> cont;
const std::size_t size = 10;
cont a(size);
for(std::size_t i = 0; i != size; ++i) {
if (a[i].ptr != 0) {
std::cerr << "POD test failed" << std::endl;
return 1;
}
}
}
#endif
return 0; return 0;
} }