Latest Results
Fix xview::element when a newaxis precedes an integral slice
make_index maps each dimension i of the underlying expression to its
slice k, then to the position of that slice in the view index:
k minus the number of integral slices before it. It counted the
integral slices before i instead of before k. The two differ when a
newaxis comes before an integral slice, so the wrong index was read:
xt::xarray<int> a = {{0, 1, 2}, {3, 4, 5}};
auto v = xt::view(a, xt::newaxis(), 1, xt::all());
v[{0, 2}]; // returned 3 instead of 5
operator() already used the slice position. element(), and the
operator[] and at-style accesses built on it, now do too.gouarin:fix-xview-element-newaxis Validate the arguments of pad and tile
pad and tile take one value, or one pair of values, per axis of the
expression and index their argument by axis. The sizes were only
checked by XTENSOR_ASSERT, which is off in release builds, and the
limits of each pad mode were not checked at all in release:
- pad with fewer pairs than axes, or pairs with fewer than two values,
read past the end of pad_width (heap-buffer-overflow);
- pad with more pairs than axes ignored the extra ones;
- wrap, periodic and symmetric with a width larger than the axis, or
reflect with a width of at least its size, and edge on an empty
axis, returned uninitialized values;
- tile with more repetitions than axes wrote past the std::array shape
of an xtensor (stack-buffer-overflow), and with fewer it built a
garbage shape;
- tile(e, n) on a 0-D expression wrote to an empty std::vector;
- negative widths or repetitions wrapped around to huge sizes.
These cases now throw std::runtime_error before the result is
allocated. The loops of tile use the dimension of the expression for
every buffer they index, which also removes the GCC 13 -O3
-Wstringop-overflow warning on its slice vector.gouarin:fix-pad-tile-validation Simplify svector::grow
Both branches of grow() allocated the new buffer and copied the
elements into it, and only the heap branch released the old buffer.
grow() now does the allocation and the copy once, then releases the old
buffer when it is on the heap. The copy uses current_size, the value
that sizes the new buffer and sets the new end. The XTENSOR_ASSERT on
the result of allocate(), which came after the buffer had been written
to, is removed: allocate() throws on failure.
The branch taken when the elements are inline was also where GCC 15 at
-O3 replaced m_begin with the inline array and, unable to bound the
size, warned that the copy reads past it (-Warray-bounds). The size is
at most N there, so the read was never out of bounds; the warning goes
away with the duplicated branch. Copying current_size elements, rather
than recomputing the count from m_end, also keeps GCC 13 from pairing a
one-element buffer with a non-empty copy when grow() is inlined into
push_back().gouarin:simplify-svector-grow Latest Branches
0%
-22%
0%
gouarin:fix-xview-element-newaxis © 2026 CodSpeed Technology