From 543e34ab9dee6004337b7ad912417eb91bf4a0b9 Mon Sep 17 00:00:00 2001 From: Antonio Sanchez Date: Fri, 5 Mar 2021 12:54:26 -0800 Subject: Re-implement move assignments. The original swap approach leads to potential undefined behavior (reading uninitialized memory) and results in unnecessary copying of data for static storage. Here we pass down the move assignment to the underlying storage. Static storage does a one-way copy, dynamic storage does a swap. Modified the tests to no longer read from the moved-from matrix/tensor, since that can lead to UB. Added a test to ensure we do not access uninitialized memory in a move. Fixes: #2119 --- test/rvalue_types.cpp | 45 +++++++++++++++++++++++++++++++++++++++++---- test/sparse_basic.cpp | 2 +- 2 files changed, 42 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/rvalue_types.cpp b/test/rvalue_types.cpp index 2eef47d1f..c20a32f79 100644 --- a/test/rvalue_types.cpp +++ b/test/rvalue_types.cpp @@ -18,6 +18,36 @@ using internal::UIntPtr; +// A Scalar that asserts for uninitialized access. +template +class SafeScalar { + public: + SafeScalar() : initialized_(false) {} + SafeScalar(const SafeScalar& other) { + *this = other; + } + SafeScalar& operator=(const SafeScalar& other) { + val_ = T(other); + initialized_ = true; + return *this; + } + + SafeScalar(T val) : val_(val), initialized_(true) {} + SafeScalar& operator=(T val) { + val_ = val; + initialized_ = true; + } + + operator T() const { + VERIFY(initialized_ && "Uninitialized access."); + return val_; + } + + private: + T val_; + bool initialized_; +}; + #if EIGEN_HAS_RVALUE_REFERENCES template void rvalue_copyassign(const MatrixType& m) @@ -94,19 +124,24 @@ void rvalue_move(const MatrixType& m) MatrixType d = m; VERIFY_IS_EQUAL(d, m); - // rvalue reference is moved + // rvalue reference is moved - copy constructor. MatrixType e_src(m); VERIFY_IS_EQUAL(e_src, m); MatrixType e_dst(std::move(e_src)); - VERIFY_IS_EQUAL(e_src, MatrixType()); VERIFY_IS_EQUAL(e_dst, m); - // rvalue reference is moved + // rvalue reference is moved - copy constructor. MatrixType f_src(m); VERIFY_IS_EQUAL(f_src, m); MatrixType f_dst = std::move(f_src); - VERIFY_IS_EQUAL(f_src, MatrixType()); VERIFY_IS_EQUAL(f_dst, m); + + // rvalue reference is moved - copy assignment. + MatrixType g_src(m); + VERIFY_IS_EQUAL(g_src, m); + MatrixType g_dst; + g_dst = std::move(g_src); + VERIFY_IS_EQUAL(g_dst, m); } #else template @@ -144,6 +179,8 @@ EIGEN_DECLARE_TEST(rvalue_types) #if EIGEN_HAS_CXX11 CALL_SUBTEST_5(rvalue_move(Eigen::Matrix,1,3>::Random().eval())); + CALL_SUBTEST_5(rvalue_move(Eigen::Matrix,1,3>::Random().eval())); + CALL_SUBTEST_5(rvalue_move(Eigen::Matrix,Eigen::Dynamic,Eigen::Dynamic>::Random(1,3).eval())); #endif } } diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index f7ad930e9..9453111b7 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -688,7 +688,7 @@ void big_sparse_triplet(Index rows, Index cols, double density) { typedef Triplet TripletType; std::vector triplets; double nelements = density * rows*cols; - VERIFY(nelements>=0 && nelements < NumTraits::highest()); + VERIFY(nelements>=0 && nelements < static_cast(NumTraits::highest())); Index ntriplets = Index(nelements); triplets.reserve(ntriplets); Scalar sum = Scalar(0); -- cgit v1.2.3