<functional>: std::function doesn't handle over-aligned types (#698)

Fixes #690.
This commit is contained in:
Alex Guteniev 2020-04-22 11:34:49 +03:00 коммит произвёл GitHub
Родитель 72c724007c
Коммит 97f9a2ce25
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 70 добавлений и 1 удалений

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

@ -795,7 +795,8 @@ private:
constexpr size_t _Space_size = (_Small_object_num_ptrs - 1) * sizeof(void*);
template <class _Impl> // determine whether _Impl must be dynamically allocated
_INLINE_VAR constexpr bool _Is_large = (_Space_size < sizeof(_Impl)) || !_Impl::_Nothrow_move::value;
_INLINE_VAR constexpr bool _Is_large = sizeof(_Impl) > _Space_size || alignof(_Impl) > alignof(max_align_t)
|| !_Impl::_Nothrow_move::value;
#if _HAS_FUNCTION_ALLOCATOR_SUPPORT
// CLASS TEMPLATE _Func_impl

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

@ -157,6 +157,7 @@ tests\Dev11_1158803_regex_thread_safety
tests\Dev11_1180290_filesystem_error_code
tests\GH_000457_system_error_message
tests\GH_000545_include_compare
tests\GH_000690_overaligned_function
tests\P0024R2_parallel_algorithms_adjacent_difference
tests\P0024R2_parallel_algorithms_adjacent_find
tests\P0024R2_parallel_algorithms_all_of

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

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

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

@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <functional>
#pragma warning(disable : 4324) // structure was padded due to alignment specifier
// SFO (Small Functor Optimization) should not happen
struct alignas(2 * alignof(std::max_align_t)) overaligned_t {
char non_empty;
void operator()(const void* const storage, const std::size_t storage_size) const {
const auto storage_ptr_value = reinterpret_cast<std::uintptr_t>(storage);
const auto this_ptr_value = reinterpret_cast<std::uintptr_t>(this);
// Platform-specific behavior not covered by Standard C++, but fine for this test
assert(this_ptr_value < storage_ptr_value || this_ptr_value >= storage_ptr_value + storage_size);
// Before C++17, alignas isn't helpful for aligning allocations via "new"
#ifdef __cpp_aligned_new
assert(this_ptr_value % alignof(overaligned_t) == 0);
#endif
}
};
// SFO should happen
struct not_overaligned_t {
char data[sizeof(overaligned_t)];
void operator()(const void* const storage, const std::size_t storage_size) const {
const auto storage_ptr_value = reinterpret_cast<std::uintptr_t>(storage);
const auto this_ptr_value = reinterpret_cast<std::uintptr_t>(this);
// Platform-specific behavior not covered by Standard C++, but fine for this test
assert(this_ptr_value >= storage_ptr_value && this_ptr_value < storage_ptr_value + storage_size);
}
};
static_assert(alignof(overaligned_t) > alignof(std::max_align_t), "overaligned_t is not overaligned");
using function_t = std::function<void(const void* storage, std::size_t storage_size)>;
struct functions_t {
function_t first{overaligned_t{}};
char smallest_pad;
function_t second{overaligned_t{}};
function_t third{overaligned_t{}};
};
int main() {
functions_t functions;
functions.first(&functions.first, sizeof(functions.first));
functions.second(&functions.second, sizeof(functions.second));
functions.third(&functions.third, sizeof(functions.third));
function_t sfo{not_overaligned_t{}};
sfo(&sfo, sizeof(sfo));
return 0;
}