On Mon, May 26, 2025 at 1:32 PM Luc Grosheintz <luc.groshei...@gmail.com> wrote:
> > > On 5/26/25 11:43, Tomasz Kaminski wrote: > > On Mon, May 26, 2025 at 11:35 AM Luc Grosheintz < > luc.groshei...@gmail.com> > > wrote: > > > >> > >> > >> On 5/22/25 15:21, Tomasz Kaminski wrote: > >>> > >>> For the stride and product computation, we should perform them in > >>> Extent::size_type, not index_type. > >>> The latter may be signed, and we may hit UB in multiplying non-zero > >>> extents, before reaching the zero. > >>> > >> > >> Then I observe the following issues: > >> > >> 1. When computing products, the integer promotion rules can interfere. > >> For simplicity let's assume that int is a 32 bit integer. Then the > >> relevant case is `uint16_t` (or unsigned short). Which is unsigned; and > >> therefore overflow shouldn't be UB. I observe that the expression > >> > >> prod *= n; > >> > >> will overflow as `int` (for large enough `n`). I believe that during the > >> computation of `prod * n` both sides are promoted to int (because the > >> range of uint16_t is contained in the range of `int`) and then > >> overflows, e.g. for n = 2**16-1. > >> > >> Note that many other small, both signed and unsigned, integers > >> semantically also overflow, but it's neither UB that's detected by > >> -fsanitize=undefined, nor a compiler error. Likely because the > >> "overflow" happens during conversion, which (in C++23) is uniquely > >> defined in [conv.integral], i.e. not UB. > >> > >> draft: https://eel.is/c++draft/conv.integral > >> N4950: 7.3.9 on p. 101 > >> > >> The solution I've come up is to not use `size_type` but > >> make_unsigned_t<decltype(index_type{} * index_type{})> > >> > >> Please let me know if there's a better solution to forcing unsigned > >> math. > >> > > I think at this point we should perform stride computation in > std::size_t. > > Because accessors are defined to accept size_t, the required_span_size() > > cannot be greater > > than maximum of size_t, and that limits our product of extents. > > > > I looked into this in the context of computing the product of > static extents. The stumbling block was that I couldn't find > a clear statement that sizeof(int) <= sizeof(size_t), or that > size_t is exempted from the integer conversion rules. > > Therefore, the concern was that the overflow issue would come > back on systems with 16-bit size_t and 32-bit int. > We could cast elements of __dyn_exts to size_t before multiplying in __ext_prod. Even use size_t in for loop: for (size_t x ; __dyn_ext()). > > I'm slightly unhappy that (on common systems) we need to use > 64-bit integers for 32-bit (or less) operations; but as you > point out, this only affects code that shouldn't be performance > sensitive. > > >> > >> Godbolt: https://godbolt.org/z/PnvaYT7vd > >> > >> 2. Let's assume we compute `__extents_prod` safely, e.g. by doing all > >> math as unsigned integers. There's several places we need to be careful: > >> > >> 2.1. layout_{right,left}::stride, these still compute products, that > >> overflow and might not be multiplied by `0` to make the answer > >> unambiguous. For an empty extent, any number is a valid stride. > Hence, > >> this only requires that we don't run into UB. > >> > >> 2.2. The default ctor of layout_stride computes the layout_right > >> strides on the fly. We can use __unsigned_prod to keep computing the > >> extents in linear time. The only requirement I'm aware of is that > the > >> strides are the same as those for layout_right (but the actual value > >> in not defined directly). > >> > >> 2.3 layout_stride::required_span_size, the current implementation > >> first scans for zeros; and only if there are none does it proceed > with > >> computing the required span size in index_type. This is safe, > because > >> the all terms in the sum are non-negative and the mandate states > that > >> the total is a representable number. Hence, all the involved terms > are > >> representable too. > >> > >> 3. For those interested in what the other two implementions do: both > >> fail in some subset of the corner cases. > >> > >> Godbolt: https://godbolt.org/z/vEYxEvMWs > >> > >> > > > >