`<mdspan>`: Fixes signed overflow in `_Fwd_prod_of_extents` (#4037)

Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
Matt Stephanson 2023-09-21 12:37:19 -07:00 коммит произвёл GitHub
Родитель 11c8fc3bfa
Коммит a577749de0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 89 добавлений и 3 удалений

Просмотреть файл

@ -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);
}
}
};

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\concepts_latest_matrix.lst

Просмотреть файл

@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <cassert>
#include <cstdint>
#include <mdspan>
#include <type_traits>
using namespace std;
struct layout_packed_upper { // LAPACK packed storage, VERY INCOMPLETE
template <class Extents>
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<make_unsigned_t<decltype(dim)>>;
const auto udim = static_cast<UType>(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<int32_t, dim, dim>;
constexpr mdspan<double, E, layout_packed_upper> m(nullptr);
static_assert(m.size() == expected_size);
static_assert(m.mapping().required_span_size() == expected_req_size);
}
{
using E = dextents<int32_t, 2>;
constexpr mdspan<double, E, layout_packed_upper> m(nullptr, dim, dim);
static_assert(m.size() == expected_size);
static_assert(m.mapping().required_span_size() == expected_req_size);
}
return 0;
}