Repository: xtensor-stack/xtensor (language: python)

Issue:
Segfault instead of exception for (illegal) resize of xtensor
I've started to test our code with XCode 11.3 on macOS 10.14. Generally `xtensor` performs well and all tests succeeded but I've just hit a new problem on this platform. The following code is taken from an internal test. It tries an illegal resize of an xtensor:
```
template<class T>
using xvector = xtensor_container<XTENSOR_DEFAULT_DATA_CONTAINER(T, XTENSOR_DEFAULT_ALLOCATOR(T)), 1, XTENSOR_DEFAULT_LAYOUT>;

xt::xvector<size_t> vNewShape({9, 9});

// should throw, because dimension mismatch and can not be reshaped correctly:
xt::xtensor<float, 1> vPaddedTensor;
vPaddedTensor.resize(vNewShape);
```
On most platforms we get a std::exception as the result, but with XCode 11.3 we get a segfault:
```
Resizing output tensor from dimensions 1 to shape 9;9
TensorPaddingTest was compiled with optimization - stepping may behave oddly; variables may not be available.
Process 68162 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x9)
    frame #0: 0x0000000100048666 TensorPaddingTest`void xt::xstrided_container<xt::xtensor_container<xt::uvector<float, xsimd::aligned_allocator<float, 32ul> >, 1ul, (xt::layout_type)1, xt::xtensor_expression_tag> >::resize<xt::xtensor_container<xt::uvector<unsigned long, xsimd::aligned_allocator<unsigned long, 32ul> >, 1ul, (this=0x0000000000000009, shape=0x00007ffeefbfe9b0, force=<unavailable>)1, xt::xtensor_expression_tag>&>(xt::xtensor_container<xt::uvector<unsigned long, xsimd::aligned_allocator<unsigned long, 32ul> >, 1ul, (xt::layout_type)1, xt::xtensor_expression_tag>&, bool) at xcontainer.hpp:918:21 [opt]
   915 	            {
   916 	                m_layout = XTENSOR_DEFAULT_LAYOUT;  // fall back to default layout
   917 	            }
-> 918 	            m_shape = xtl::forward_sequence<shape_type, S>(shape);
   919 	            resize_container(m_strides, dim);
   920 	            resize_container(m_backstrides, dim);
   921 	            size_type data_size = compute_strides<D::static_layout>(m_shape, m_layout, m_strides, m_backstrides);
Target 0: (TensorPaddingTest) stopped.
```


Discussion / hints:
I've just run into this issue again, this time with clang-cl on MSVC. So its certainly a clang thing, not specific to macOS. Anything I can do to help move this forward?
I could reproduce the issue now with a much simpler use case! Is it possible that the following (illegal) code does not throw? At least I could trace this through `inline void xstrided_container<D>::resize(S&& shape, bool force)` and there is no check if the dimensions match. I guess for an `xt::xtensor` this should be illegal? :-)
```
xt::xtensor<float, 1> vTensor;
vTensor.resize(xt::shape({ 3, 3 }));
```

Indeed, there is no check in the resize method, good catch!
Hi Johan, do you think this is something that you could look into sometime? Its actually quite a bit a nasty issue...
Hi, yes, I have some urgent things to finish, and then I can do a pass on xtensor to pop some issues from the stack. Keeping this one in my notifications so that I don't forget it.
Thanks a million @JohanMabille , it would be highly appreciated! It comes up as an issue every now and then and we did not get around to fix it ourselves...

Fix patch:
diff --git a/include/xtensor/xcontainer.hpp b/include/xtensor/xcontainer.hpp
index 06917bcaa..7a116804c 100644
--- a/include/xtensor/xcontainer.hpp
+++ b/include/xtensor/xcontainer.hpp
@@ -898,6 +898,18 @@ namespace xt
             (void) size;
             XTENSOR_ASSERT_MSG(c.size() == size, "Trying to resize const data container with wrong size.");
         }
+
+        template <class S, class T>
+        constexpr bool check_resize_dimension(const S&, const T&)
+        {
+            return true;
+        }
+
+        template <class T, size_t N, class S>
+        constexpr bool check_resize_dimension(const std::array<T, N>&, const S& s)
+        {
+            return N == s.size();
+        }
     }
 
     /**
@@ -911,6 +923,8 @@ namespace xt
     template <class S>
     inline void xstrided_container<D>::resize(S&& shape, bool force)
     {
+        XTENSOR_ASSERT_MSG(detail::check_resize_dimension(m_shape, shape),
+                           "cannot change the number of dimensions of xtensor")
         std::size_t dim = shape.size();
         if (m_shape.size() != dim || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force)
         {
@@ -938,6 +952,8 @@ namespace xt
     template <class S>
     inline void xstrided_container<D>::resize(S&& shape, layout_type l)
     {
+        XTENSOR_ASSERT_MSG(detail::check_resize_dimension(m_shape, shape),
+                           "cannot change the number of dimensions of xtensor")
         if (base_type::static_layout != layout_type::dynamic && l != base_type::static_layout)
         {
             XTENSOR_THROW(std::runtime_error, "Cannot change layout_type if template parameter not layout_type::dynamic.");
@@ -957,6 +973,8 @@ namespace xt
     template <class S>
     inline void xstrided_container<D>::resize(S&& shape, const strides_type& strides)
     {
+        XTENSOR_ASSERT_MSG(detail::check_resize_dimension(m_shape, shape),
+                           "cannot change the number of dimensions of xtensor")
         if (base_type::static_layout != layout_type::dynamic)
         {
             XTENSOR_THROW(std::runtime_error,
diff --git a/include/xtensor/xexception.hpp b/include/xtensor/xexception.hpp
index d35dada45..3449704df 100644
--- a/include/xtensor/xexception.hpp
+++ b/include/xtensor/xexception.hpp
@@ -208,7 +208,7 @@ namespace xt
         {
             XTENSOR_THROW(std::out_of_range,
                           "Number of arguments (" + std::to_string(sizeof...(Args)) +
-                          ") us greater than the number of dimensions (" +
+                          ") is greater than the number of dimensions (" +
                           std::to_string(shape.size()) + ")");
         }
     }


Test patch:
diff --git a/test/test_xarray.cpp b/test/test_xarray.cpp
index af525e1eb..2a23de052 100644
--- a/test/test_xarray.cpp
+++ b/test/test_xarray.cpp
@@ -147,7 +147,14 @@ namespace xt
     TEST(xarray, resize)
     {
         xarray_dynamic a;
+        std::vector<size_t> shape = {2, 2};
+        xarray_dynamic::strides_type strides = {2, 1};
         test_resize(a);
+#ifdef XTENSOR_ENABLE_ASSERT
+        EXPECT_NO_THROW(a.resize(shape));
+        EXPECT_NO_THROW(a.resize(shape, layout_type::row_major));
+        EXPECT_NO_THROW(a.resize(shape, strides));
+#endif
     }
 
     TEST(xarray, reshape)
diff --git a/test/test_xtensor.cpp b/test/test_xtensor.cpp
index f9c2fa9be..79e913374 100644
--- a/test/test_xtensor.cpp
+++ b/test/test_xtensor.cpp
@@ -171,6 +171,15 @@ namespace xt
     {
         xtensor_dynamic a;
         test_resize<xtensor_dynamic, storage_type>(a);
+
+#ifdef XTENSOR_ENABLE_ASSERT
+        xtensor_dynamic b;
+        std::vector<size_t> s = { 2u, 2u };
+        xtensor_dynamic::strides_type strides = {2u, 1u};
+        EXPECT_THROW(b.resize(s), std::runtime_error);
+        EXPECT_THROW(b.resize(s, layout_type::dynamic), std::runtime_error);
+        EXPECT_THROW(b.resize(s, strides), std::runtime_error);
+#endif
     }
 
     TEST(xtensor, reshape)