Skip to content

Check the dimension of runtime shapes given to xtensor - #2962

Open
gouarin wants to merge 1 commit into
xtensor-stack:masterfrom
gouarin:fix-xtensor-rank-checks
Open

gouarin wants to merge 1 commit into
xtensor-stack:masterfrom
gouarin:fix-xtensor-rank-checks

Conversation

@gouarin

@gouarin gouarin commented Oct 29, 2026

Copy link
Copy Markdown
Member

Checklist

  • The title and commit message(s) are descriptive.
  • Small commits made to fix your PR have been squashed to avoid history pollution.
  • Tests have been added for new features or bug fixes.
  • API of new functions and classes are documented (no public API changes).

Description

The shape of an xtensor<T, N> is a std::array<std::size_t, N>. resize checks that a runtime shape has N values, but from_shape only had an XTENSOR_ASSERT and reshape had no check, so a shape of the wrong length was copied past the array:

xt::xtensor<double, 1>::from_shape(std::vector<std::size_t>{2, 3});  // stack-buffer-overflow
xt::xtensor<double, 1> t = {1., 2., 3., 4., 5., 6.};
t.reshape(std::vector<std::size_t>{2, 3});                           // same
xt::xarray<double> x = {{0.5, 1.5}, {2.5, 3.5}};
xt::interp(x, xp, fp);  // builds its xtensor<T, 1> result with from_shape(x.shape())

from_shape and both reshape overloads now use the same XTENSOR_PRECONDITION as resize. interp also checks its arguments up front: x, xp and fp must be 1-D, xp must not be empty, and fp must have the length of xp. Before, a 2-D xp or a short fp was read out of bounds, and a 0-D x gave a result with an uninitialized shape.

This removes the GCC 13/15 -Warray-bounds and -Wmaybe-uninitialized warnings on ret in xtensor.hpp (from_shape, reached from interp in test_extended_xmath_interp).

xtensor.change_dimension and xmath.interp_invalid_arguments fail on master and pass with the fix, also under AddressSanitizer and UBSan.

The shape of an xtensor<T, N> is a std::array<std::size_t, N>. resize()
checks that a runtime shape has N values, but from_shape() only had an
XTENSOR_ASSERT, off in release builds, and reshape() had no check. A
shape of the wrong length was copied past the std::array, a
stack-buffer-overflow, as in
xtensor<double, 1>::from_shape(std::vector<std::size_t>{2, 3}).

interp() builds its xtensor<T, 1> result with from_shape(x.shape()), so
a 2-D x overflowed the same way, and a 0-D x gave a result with an
uninitialized shape. It also read a 2-D xp or a short fp out of bounds.

from_shape() and both reshape() overloads now use the same
XTENSOR_PRECONDITION as resize(). interp() checks up front that x, xp
and fp are 1-D, that xp is not empty and that fp has the length of xp.

This removes the GCC 13 and 15 -Warray-bounds and -Wmaybe-uninitialized
warnings on the copy into the shape in from_shape(), reached from
interp() in test_extended_xmath_interp.
@codspeed

codspeed Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

1 warning

⚠️ Unable to measure the execution of 1 benchmark

This benchmark measured no execution time, so its result is not comparable and counts as unchanged. This usually happens when the compiler removes the code under test.

Prevent compiler optimizations

See affected benchmarks

✅ 255 untouched benchmarks


Comparing gouarin:fix-xtensor-rank-checks (4836e24) with master (57f3d07)

Open in CodSpeed

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant