From d213a0bcea2344aa3f6c9856da9f5b2a26ccec25 Mon Sep 17 00:00:00 2001 From: Antonio Sanchez Date: Wed, 21 Apr 2021 15:45:31 -0700 Subject: DenseStorage safely copy/swap. Fixes #2229. For dynamic matrices with fixed-sized storage, only copy/swap elements that have been set. Otherwise, this leads to inefficient copying, and potential UB for non-initialized elements. --- test/SafeScalar.h | 30 +++++++++++ test/dense_storage.cpp | 144 ++++++++++++++++++++++++++++++++++++------------- test/rvalue_types.cpp | 31 +---------- 3 files changed, 139 insertions(+), 66 deletions(-) create mode 100644 test/SafeScalar.h (limited to 'test') diff --git a/test/SafeScalar.h b/test/SafeScalar.h new file mode 100644 index 000000000..c5cb75717 --- /dev/null +++ b/test/SafeScalar.h @@ -0,0 +1,30 @@ + +// 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_; +}; diff --git a/test/dense_storage.cpp b/test/dense_storage.cpp index 7fa25859d..36ccbb02c 100644 --- a/test/dense_storage.cpp +++ b/test/dense_storage.cpp @@ -8,17 +8,16 @@ // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #include "main.h" +#include "AnnoyingScalar.h" +#include "SafeScalar.h" #include -template -void dense_storage_copy() +template +void dense_storage_copy(int rows, int cols) { - static const int Size = ((Rows==Dynamic || Cols==Dynamic) ? Dynamic : Rows*Cols); - typedef DenseStorage DenseStorageType; + typedef DenseStorage DenseStorageType; - const int rows = (Rows==Dynamic) ? 4 : Rows; - const int cols = (Cols==Dynamic) ? 3 : Cols; const int size = rows*cols; DenseStorageType reference(size, rows, cols); T* raw_reference = reference.data(); @@ -31,14 +30,11 @@ void dense_storage_copy() VERIFY_IS_EQUAL(raw_reference[i], raw_copied_reference[i]); } -template -void dense_storage_assignment() +template +void dense_storage_assignment(int rows, int cols) { - static const int Size = ((Rows==Dynamic || Cols==Dynamic) ? Dynamic : Rows*Cols); - typedef DenseStorage DenseStorageType; + typedef DenseStorage DenseStorageType; - const int rows = (Rows==Dynamic) ? 4 : Rows; - const int cols = (Cols==Dynamic) ? 3 : Cols; const int size = rows*cols; DenseStorageType reference(size, rows, cols); T* raw_reference = reference.data(); @@ -52,6 +48,34 @@ void dense_storage_assignment() VERIFY_IS_EQUAL(raw_reference[i], raw_copied_reference[i]); } +template +void dense_storage_swap(int rows0, int cols0, int rows1, int cols1) +{ + typedef DenseStorage DenseStorageType; + + const int size0 = rows0*cols0; + DenseStorageType a(size0, rows0, cols0); + for (int i=0; i(i); + } + + const int size1 = rows1*cols1; + DenseStorageType b(size1, rows1, cols1); + for (int i=0; i(-i); + } + + a.swap(b); + + for (int i=0; i(i)); + } + + for (int i=0; i(-i)); + } +} + template void dense_storage_alignment() { @@ -78,30 +102,78 @@ void dense_storage_alignment() #endif } -EIGEN_DECLARE_TEST(dense_storage) -{ - dense_storage_copy(); - dense_storage_copy(); - dense_storage_copy(); - dense_storage_copy(); - - dense_storage_copy(); - dense_storage_copy(); - dense_storage_copy(); - dense_storage_copy(); +template +void dense_storage_tests() { + // Dynamic Storage. + dense_storage_copy(4, 3); + dense_storage_copy(4, 3); + dense_storage_copy(4, 3); + // Fixed Storage. + dense_storage_copy(4, 3); + dense_storage_copy(4, 3); + dense_storage_copy(4, 3); + dense_storage_copy(4, 3); + // Fixed Storage with Uninitialized Elements. + dense_storage_copy(4, 3); + dense_storage_copy(4, 3); + dense_storage_copy(4, 3); - dense_storage_assignment(); - dense_storage_assignment(); - dense_storage_assignment(); - dense_storage_assignment(); - - dense_storage_assignment(); - dense_storage_assignment(); - dense_storage_assignment(); - dense_storage_assignment(); + // Dynamic Storage. + dense_storage_assignment(4, 3); + dense_storage_assignment(4, 3); + dense_storage_assignment(4, 3); + // Fixed Storage. + dense_storage_assignment(4, 3); + dense_storage_assignment(4, 3); + dense_storage_assignment(4, 3); + dense_storage_assignment(4, 3); + // Fixed Storage with Uninitialized Elements. + dense_storage_assignment(4, 3); + dense_storage_assignment(4, 3); + dense_storage_assignment(4, 3); + + // Dynamic Storage. + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 2, 1); + dense_storage_swap(2, 1, 4, 3); + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 2, 3); + dense_storage_swap(2, 3, 4, 3); + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 4, 1); + dense_storage_swap(4, 1, 4, 3); + // Fixed Storage. + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 2, 1); + dense_storage_swap(2, 1, 4, 3); + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 4, 1); + dense_storage_swap(4, 1, 4, 3); + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 2, 3); + dense_storage_swap(2, 3, 4, 3); + // Fixed Storage with Uninitialized Elements. + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 2, 1); + dense_storage_swap(2, 1, 4, 3); + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 4, 1); + dense_storage_swap(4, 1, 4, 3); + dense_storage_swap(4, 3, 4, 3); + dense_storage_swap(4, 3, 2, 3); + dense_storage_swap(2, 3, 4, 3); + + dense_storage_alignment(); + dense_storage_alignment(); + dense_storage_alignment(); + dense_storage_alignment(); +} - dense_storage_alignment(); - dense_storage_alignment(); - dense_storage_alignment(); - dense_storage_alignment(); +EIGEN_DECLARE_TEST(dense_storage) +{ + dense_storage_tests(); + dense_storage_tests(); + dense_storage_tests >(); + dense_storage_tests(); } diff --git a/test/rvalue_types.cpp b/test/rvalue_types.cpp index c20a32f79..2c9999ce8 100644 --- a/test/rvalue_types.cpp +++ b/test/rvalue_types.cpp @@ -13,41 +13,12 @@ #if EIGEN_HAS_CXX11 #include "MovableScalar.h" #endif +#include "SafeScalar.h" #include 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) -- cgit v1.2.3