diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 12e021929..a603de5f0 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -348,11 +348,13 @@ public: if constexpr (_Extents::rank() == 0) { return 1; } else { - typename _Extents::index_type _Result = 1; + // Use an unsigned type to prevent overflow when called from mdspan::size. + typename _Extents::size_type _Result = 1; for (size_t _Dim = 0; _Dim < _Idx; ++_Dim) { - _Result *= _Exts.extent(_Dim); + _Result *= static_cast<_Extents::size_type>(_Exts.extent(_Dim)); } - return _Result; + + return static_cast<_Extents::index_type>(_Result); } } }; diff --git a/tests/std/test.lst b/tests/std/test.lst index 7d11a6913..98d008402 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -231,6 +231,7 @@ tests\GH_003676_format_large_hh_mm_ss_values tests\GH_003735_char_traits_signatures tests\GH_003840_tellg_when_reading_lf_file_in_text_mode tests\GH_003867_output_nan +tests\GH_004023_mdspan_fwd_prod_overflow tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function diff --git a/tests/std/tests/GH_004023_mdspan_fwd_prod_overflow/env.lst b/tests/std/tests/GH_004023_mdspan_fwd_prod_overflow/env.lst new file mode 100644 index 000000000..18e2d7c71 --- /dev/null +++ b/tests/std/tests/GH_004023_mdspan_fwd_prod_overflow/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/GH_004023_mdspan_fwd_prod_overflow/test.compile.pass.cpp b/tests/std/tests/GH_004023_mdspan_fwd_prod_overflow/test.compile.pass.cpp new file mode 100644 index 000000000..48095f66f --- /dev/null +++ b/tests/std/tests/GH_004023_mdspan_fwd_prod_overflow/test.compile.pass.cpp @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +struct layout_packed_upper { // LAPACK packed storage, VERY INCOMPLETE + template + class mapping { + public: + using extents_type = Extents; + using index_type = extents_type::index_type; + using size_type = extents_type::size_type; + using rank_type = extents_type::rank_type; + using layout_type = layout_packed_upper; + + constexpr mapping() noexcept = default; + constexpr mapping(const extents_type& ex_) : ex{ex_} {} + + constexpr const extents_type& extents() const { + return ex; + } + + constexpr index_type required_span_size() const { + if (dim % 2 == 0) { + return (dim / 2) * (dim + 1); + } else { + return ((dim + 1) / 2) * dim; + } + } + + private: + extents_type ex = extents_type(); + index_type dim = ex.extent(0); + }; +}; + +int main() { + constexpr int32_t dim = 47'000; // sqrt(2^32) > dim > sqrt(2^31), dim assumed even below + constexpr auto expected_size = [] { + int32_t unused; + bool overflow = _Mul_overflow(dim, dim, unused); + assert(overflow); + + using UType = remove_cv_t>; + const auto udim = static_cast(dim); + UType result{}; + overflow = _Mul_overflow(udim, udim, result); + assert(!overflow); + return result; + }(); + + constexpr auto expected_req_size = [] { + int32_t result{}; + const bool overflow = _Mul_overflow(dim / 2, dim + 1, result); + assert(!overflow); + return result; + }(); + + { + using E = extents; + constexpr mdspan m(nullptr); + static_assert(m.size() == expected_size); + static_assert(m.mapping().required_span_size() == expected_req_size); + } + + { + using E = dextents; + constexpr mdspan m(nullptr, dim, dim); + static_assert(m.size() == expected_size); + static_assert(m.mapping().required_span_size() == expected_req_size); + } + + return 0; +}