From 389172412c139e727093f365e0bfbdf6142f2da1 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 12:32:18 +0200 Subject: [PATCH 001/131] stacktrace initial implementation --- stl/CMakeLists.txt | 21 ++- stl/inc/stacktrace | 300 +++++++++++++++++++++++++++++++++++ stl/src/msvcp_stacktrace.def | 6 + stl/src/stacktrace.cpp | 177 +++++++++++++++++++++ 4 files changed, 502 insertions(+), 2 deletions(-) create mode 100644 stl/inc/stacktrace create mode 100644 stl/src/msvcp_stacktrace.def create mode 100644 stl/src/stacktrace.cpp diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 82d2d1e970..8e92693698 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -420,12 +420,17 @@ set(SOURCES_SATELLITE_CODECVT_IDS ${CMAKE_CURRENT_LIST_DIR}/src/ulocale.cpp ) +set(SOURCES_SATELLITE_STACKTRACE + ${CMAKE_CURRENT_LIST_DIR}/src/stacktrace.cpp +) + # Objs that exist only in libcpmt[d][01].lib. set(STATIC_SOURCES ${SOURCES_SATELLITE_1} ${SOURCES_SATELLITE_2} ${SOURCES_SATELLITE_ATOMIC_WAIT} ${SOURCES_SATELLITE_CODECVT_IDS} + ${SOURCES_SATELLITE_STACKTRACE} ) # Objs that exist in all satellite DLLs @@ -518,6 +523,18 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "${_ATOMIC_WAIT_OUTPUT_NAME}") target_link_options(msvcp${D_SUFFIX}_atomic_wait PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") + # msvcp140_stacktrace.dll (the stacktrace satellite) + add_library(msvcp${D_SUFFIX}_stacktrace_objects OBJECT ${SOURCES_SATELLITE_STACKTRACE}) + target_compile_definitions(msvcp${D_SUFFIX}_stacktrace_objects PRIVATE "_BUILDING_SATELLITE_STACKTRACE;_DLL;${THIS_CONFIG_DEFINITIONS}") + target_compile_options(msvcp${D_SUFFIX}_stacktrace_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") + + add_library(msvcp${D_SUFFIX}_stacktrace SHARED "${CMAKE_CURRENT_LIST_DIR}/src/msvcp_stacktrace.def") + target_link_libraries(msvcp${D_SUFFIX}_stacktrace PRIVATE msvcp${D_SUFFIX}_stacktrace_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "Dbghelp.lib") + set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_stacktrace${D_SUFFIX}${VCLIBS_SUFFIX}") + set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_stacktrace${VCLIBS_SUFFIX}") + target_link_options(msvcp${D_SUFFIX}_stacktrace PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") + # msvcp140_codecvt_ids.dll add_library(msvcp${D_SUFFIX}_codecvt_ids_objects OBJECT ${SOURCES_SATELLITE_CODECVT_IDS}) target_compile_definitions(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE "_BUILDING_SATELLITE_CODECVT_IDS;_DLL;${THIS_CONFIG_DEFINITIONS}") @@ -533,8 +550,8 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO # import library add_library(msvcp${D_SUFFIX}_implib STATIC ${HEADERS}) target_link_libraries(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX}_implib_objects) - add_dependencies(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX} msvcp_1${D_SUFFIX} msvcp_2${D_SUFFIX} msvcp${D_SUFFIX}_atomic_wait msvcp${D_SUFFIX}_codecvt_ids) - set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$;$") + add_dependencies(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX} msvcp_1${D_SUFFIX} msvcp_2${D_SUFFIX} msvcp${D_SUFFIX}_atomic_wait msvcp${D_SUFFIX}_codecvt_ids msvcp${D_SUFFIX}_stacktrace) + set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$;$;$") set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES ARCHIVE_OUTPUT_NAME "msvcprt${D_SUFFIX}") endfunction() diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace new file mode 100644 index 0000000000..939c112184 --- /dev/null +++ b/stl/inc/stacktrace @@ -0,0 +1,300 @@ +// stack standard header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once +#ifndef _STACKSTRACE_ +#define _STACKSTRACE_ +#include +#if _STL_COMPILER_PREPROCESSOR + +#if !_HAS_CXX23 +#pragma message("The contents of are available only with C++23 or later.") +#else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv + +#include +#include +#include +#include + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +unsigned short __stdcall __std_stacktrace_capture( + unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash); + +[[nodiscard]] _STD string __stdcall __std_stacktrace_description(void* _Address); +[[nodiscard]] _STD string __stdcall __std_stacktrace_source_file(void* _Address); +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(void* _Address); + +_STD_BEGIN + +// 20.?.4, class stacktrace_entry +class stacktrace_entry { +public: + using native_handle_type = void*; + + constexpr stacktrace_entry() noexcept = default; + constexpr stacktrace_entry(const stacktrace_entry& other) noexcept = default; + constexpr stacktrace_entry& operator=(const stacktrace_entry& other) noexcept = default; + + ~stacktrace_entry() = default; + + [[nodiscard]] constexpr native_handle_type native_handle() const noexcept { + return _Address; + } + + [[nodiscard]] constexpr explicit operator bool() const noexcept { + return _Address != nullptr; + } + + [[nodiscard]] string description() const { + return __std_stacktrace_description(_Address); + } + + [[nodiscard]] string source_file() const { + return __std_stacktrace_source_file(_Address); + } + + [[nodiscard]] uint_least32_t source_line() const { + return __std_stacktrace_source_line(_Address); + } + + [[nodiscard]] friend constexpr bool operator==( + const stacktrace_entry& x, const stacktrace_entry& y) noexcept = default; + + [[nodiscard]] friend constexpr strong_ordering operator<=>( + const stacktrace_entry& x, const stacktrace_entry& y) noexcept = default; + +private: + void* _Address = nullptr; +}; + +template +class basic_stacktrace { +private: + using _Frames_t = vector; + +public: + using value_type = stacktrace_entry; + using const_reference = const value_type&; + using reference = value_type&; + using const_iterator = _Frames_t::const_iterator; + using iterator = const_iterator; + using reverse_iterator = _STD reverse_iterator; + using const_reverse_iterator = _STD reverse_iterator; + using difference_type = ptrdiff_t; + using size_type = size_t; + using allocator_type = _Al; + + [[nodiscard]] static basic_stacktrace current(const allocator_type& _Alloc = allocator_type()) noexcept { + return basic_stacktrace(_Internal_t{}, 0, _Max_frames, _Alloc); + } + + [[nodiscard]] static basic_stacktrace current( + size_type _Skip, const allocator_type& _Alloc = allocator_type()) noexcept { + return basic_stacktrace(_Internal_t{}, _Skip, _Max_frames, _Alloc); + } + + [[nodiscard]] static basic_stacktrace current( + size_type _Skip, size_type _Max_depth, const allocator_type& _Alloc = allocator_type()) noexcept { + return basic_stacktrace(_Internal_t{}, _Skip, (_STD max)(_Max_depth, _Max_frames), _Alloc); + } + + basic_stacktrace() noexcept(is_nothrow_default_constructible_v) = default; + explicit basic_stacktrace(const allocator_type& _Alloc) noexcept : _Frames(_Alloc) {} + + basic_stacktrace(const basic_stacktrace&) = default; + basic_stacktrace(basic_stacktrace&&) noexcept = default; + basic_stacktrace(const basic_stacktrace& _Other, const allocator_type& _Alloc) + : _Frames(_Other._Frames, _Alloc), _Hash(_Other._Hash) {} + + basic_stacktrace(basic_stacktrace&& _Other, const allocator_type& _Alloc) + : _Frames(move(_Other._Frames), _Alloc), _Hash(_Other._Hash) {} + + basic_stacktrace& operator=(const basic_stacktrace&) = default; + basic_stacktrace& operator=(basic_stacktrace&& other) noexcept(_Noex_move) = default; + + ~basic_stacktrace() = default; + + [[nodiscard]] allocator_type get_allocator() const noexcept { + return _Frames.get_allocator(); + } + + [[nodiscard]] const_iterator begin() const noexcept { + return _Frames.cbegin(); + } + + [[nodiscard]] const_iterator end() const noexcept { + return _Frames.cend(); + } + + [[nodiscard]] const_reverse_iterator rbegin() const noexcept { + return _Frames.crbegin(); + } + + [[nodiscard]] const_reverse_iterator rend() const noexcept { + return _Frames.crend(); + } + + [[nodiscard]] const_iterator cbegin() const noexcept { + return _Frames.cbegin(); + } + + [[nodiscard]] const_iterator cend() const noexcept { + return _Frames.cend(); + } + + [[nodiscard]] const_reverse_iterator crbegin() const noexcept { + return _Frames.crbegin(); + } + + [[nodiscard]] const_reverse_iterator crend() const noexcept { + return _Frames.crend(); + } + + [[nodiscard]] bool empty() const noexcept { + return _Frames.empty(); + } + + size_type size() const noexcept { + return _Frames.size(); + } + + size_type max_size() const noexcept { + return _Frames.max_size(); + } + + const_reference operator[](size_type) const { + return _Frames[size_type]; + } + + const_reference at(size_type) const { + return _Frames.at(size_type); + } + + template + friend bool operator==(const basic_stacktrace& x, const basic_stacktrace<_Al2>& y) noexcept { + return _Hash == _Hash && _Frames == _Frames; + } + + template + friend strong_ordering operator<=>(const basic_stacktrace& x, const basic_stacktrace<_Al2>& y) noexcept { + if (_Hash != _Hash) { + return _Hash <=> _Hash; + } else { + return _Frames <=> _Frames; + } + } + + void swap(basic_stacktrace& _Other) noexcept( + allocator_traits<_Al>::propagate_on_container_swap::value || allocator_traits<_Al>::is_always_equal::value) { + _STD swap(_Frames, _Other._Frames); + _STD swap(_Hash, _Other._Hash); + } + + unsigned long _Get_hash() const { + return _Hash; + } + +private: + static constexpr size_t _Max_frames = 0xFFFF; + + bool _Noex_move = allocator_traits<_Al>::propagate_on_container_move_assignment::value + || allocator_traits<_Al>::is_always_equal::value; + + struct _Internal_t {}; + + basic_stacktrace(_Internal_t, size_type _Skip, size_type _Max_depth, const allocator_type& _Alloc) + : _Frames(_Max_depth) { + _Frames.resize(__std_stacktrace_capture(static_cast(_Skip), + static_cast(_Max_depth), reinterpret_cast(_Frames.data()), &_Hash)); + } + + _Frames_t _Frames; + unsigned long _Hash = 0; +}; + +// basic_stacktrace typedef names +using stacktrace = basic_stacktrace>; + +// 20.?.6, non-member functions +template +void swap(basic_stacktrace& _Ax, basic_stacktrace& _Bx) noexcept(noexcept(_Ax.swap(_Bx))) { + return _Ax.swap(_Bx); +} + +string to_string(const stacktrace_entry& _Fx) { + string _Result; + auto _Line = _Fx.source_line(); + auto _Desc = _Fx.description(); + + if (_Line != 0) { + _Result = _Fx.source_file() + "(" + to_string(_Line) + ")"; + } + + if (!_Desc.empty()) { + if (_Result.empty()) { + _Result = move(_Desc); + } else { + _Result = _Result + " " + _Desc; + } + } + + return _Result; +} + +template +string to_string(const basic_stacktrace& _St) { + string _Result; + for (auto& _Entry : _St) { + string _Entry_str = to_string(_Entry); + if (!_Result.empty()) { + _Result.push_back('\n'); + _Result.append(_Entry_str); + } else { + _Result = move(_Entry_str); + } + } + return _Result; +} + +template +basic_ostream& operator<<(basic_ostream& _Os, const stacktrace_entry& _Fx) { + return _Os << to_string(_Fx); +} + +template +basic_ostream& operator<<(basic_ostream& _Os, const basic_stacktrace& _Fx) { + return _Os << to_string(_Fx); +} + +template <> +struct hash : private hash { + size_t operator()(const stacktrace_entry& _Val) const { + return hash::operator()(_Val.native_handle()); + } +}; + +template +struct hash> { + size_t operator()(const basic_stacktrace& _Val) const { + return _Val; + } +}; + +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // ^^^ _HAS_CXX23 ^^^ + +#endif // _STL_COMPILER_PREPROCESSOR +#endif // _STACK_ diff --git a/stl/src/msvcp_stacktrace.def b/stl/src/msvcp_stacktrace.def new file mode 100644 index 0000000000..a804fd0dc4 --- /dev/null +++ b/stl/src/msvcp_stacktrace.def @@ -0,0 +1,6 @@ + +EXPORTS + __std_stacktrace_capture + __std_stacktrace_description + __std_stacktrace_source_file + __std_stacktrace_source_line diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp new file mode 100644 index 0000000000..6b34839a92 --- /dev/null +++ b/stl/src/stacktrace.cpp @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +// clang-format off +#include +#include +// clang-format on + +#pragma comment(lib, "Dbghelp.lib") + +namespace { + + static constexpr std::size_t max_line_size = 2000; + static constexpr std::size_t max_file_size = 260; + + static constexpr std::size_t table_size_power_of_two_factor = 10; + + static constexpr std::size_t table_size = 1 << table_size_power_of_two_factor; + + static constexpr SYMBOL_INFO InitSymbolInfo() { + SYMBOL_INFO result = {}; + result.SizeOfStruct = sizeof(SYMBOL_INFO); + result.MaxNameLen = max_line_size; + return result; + } + + struct stacktrace_address_table_entry_t { + void* address = nullptr; + bool is_description_valid = false; + bool is_line_valid = false; + IMAGEHLP_LINE64 line = {sizeof(IMAGEHLP_LINE64)}; + SYMBOL_INFO info = InitSymbolInfo(); + wchar_t buffer[max_line_size]; + }; + + static stacktrace_address_table_entry_t stacktrace_address_table[table_size]; + + class _NODISCARD srw_lock_guard { + public: + explicit srw_lock_guard(SRWLOCK& locked_) noexcept : locked(&locked_) { + AcquireSRWLockExclusive(locked); + } + + ~srw_lock_guard() { + ReleaseSRWLockExclusive(locked); + } + + srw_lock_guard(const srw_lock_guard&) = delete; + srw_lock_guard& operator=(const srw_lock_guard&) = delete; + + private: + SRWLOCK* locked; + }; + + class stacktrace_global_data_t { + public: + stacktrace_global_data_t() = default; + + ~stacktrace_global_data_t() { + if (initialized) { + SymCleanup(process_handle); + } + + if (process_handle) { + ::CloseHandle(process_handle); + } + } + + stacktrace_global_data_t(const stacktrace_global_data_t&) = delete; + stacktrace_global_data_t& operator=(const stacktrace_global_data_t) = delete; + + static stacktrace_address_table_entry_t& hash_table_entry(void* address) { + auto index = reinterpret_cast(address); + index ^= index >> table_size_power_of_two_factor; + index &= (1 << table_size_power_of_two_factor) - 1; + return stacktrace_address_table[index]; + } + + std::string description(void* address) { + auto& entry = hash_table_entry(address); + srw_lock_guard lock{mutex}; + clear_if_wrong_address(entry, address); + + if (!entry.is_description_valid) { + bool success = try_initialize() + && SymFromAddr(process_handle, reinterpret_cast(address), nullptr, &entry.info); + if (!success) { + entry.info.NameLen = 0; + } + entry.is_description_valid = true; + } + + return std::string(entry.info.Name, entry.info.NameLen); + } + + std::string source_file(void* address) { + auto& entry = hash_table_entry(address); + srw_lock_guard lock{mutex}; + + initialize_line(entry, address); + + return entry.line.FileName; + } + + unsigned source_line(void* address) { + auto& entry = hash_table_entry(address); + srw_lock_guard lock{mutex}; + + initialize_line(entry, address); + + return entry.line.LineNumber; + } + + private: + bool try_initialize() { + if (!initialize_attepted) { + initialized = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), + &process_handle, PROCESS_QUERY_INFORMATION, false, 0) + && SymInitialize(process_handle, nullptr, true); + + initialize_attepted = true; + } + + return initialized; + } + + void clear_if_wrong_address(stacktrace_address_table_entry_t& entry, void* address) { + if (entry.address != address) { + entry.is_description_valid = false; + entry.is_line_valid = false; + entry.address = address; + } + } + + void initialize_line(stacktrace_address_table_entry_t& entry, void* address) { + clear_if_wrong_address(entry, address); + + if (!entry.is_line_valid) { + bool success = try_initialize() + && SymFromAddr(process_handle, reinterpret_cast(address), nullptr, &entry.info); + if (!success) { + entry.info.NameLen = 0; + } + entry.is_line_valid = true; + } + } + + + SRWLOCK mutex = SRWLOCK_INIT; + HANDLE process_handle = nullptr; + bool initialized = false; + bool initialize_attepted = false; + }; + + static stacktrace_global_data_t stacktrace_global_data; + +} // namespace + +unsigned short __stdcall __std_stacktrace_capture( + unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash) { + return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); +} + +[[nodiscard]] _STD string __stdcall __std_stacktrace_description(void* _Address) { + return stacktrace_global_data.description(_Address); +} + +[[nodiscard]] _STD string __stdcall __std_stacktrace_source_file(void* _Address) { + return stacktrace_global_data.source_file(_Address); +} + +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(void* _Address) { + return stacktrace_global_data.source_line(_Address); +} From 99431527046e050498a313d5e280f9363a181c4a Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 19:35:02 +0200 Subject: [PATCH 002/131] fix line --- stl/inc/stacktrace | 21 +++++++++++++-------- stl/src/stacktrace.cpp | 12 +++++++++--- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 939c112184..ab840774d7 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -93,17 +93,26 @@ public: using allocator_type = _Al; [[nodiscard]] static basic_stacktrace current(const allocator_type& _Alloc = allocator_type()) noexcept { - return basic_stacktrace(_Internal_t{}, 0, _Max_frames, _Alloc); + basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Alloc); + _Result._Frames.resize(__std_stacktrace_capture(0, static_cast(_Max_frames), + reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); + return _Result; } [[nodiscard]] static basic_stacktrace current( size_type _Skip, const allocator_type& _Alloc = allocator_type()) noexcept { - return basic_stacktrace(_Internal_t{}, _Skip, _Max_frames, _Alloc); + basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Alloc); + _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip), + static_cast(_Max_frames), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); + return _Result; } [[nodiscard]] static basic_stacktrace current( size_type _Skip, size_type _Max_depth, const allocator_type& _Alloc = allocator_type()) noexcept { - return basic_stacktrace(_Internal_t{}, _Skip, (_STD max)(_Max_depth, _Max_frames), _Alloc); + basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Alloc); + _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip), + static_cast(_Max_depth), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); + return _Result; } basic_stacktrace() noexcept(is_nothrow_default_constructible_v) = default; @@ -210,11 +219,7 @@ private: struct _Internal_t {}; - basic_stacktrace(_Internal_t, size_type _Skip, size_type _Max_depth, const allocator_type& _Alloc) - : _Frames(_Max_depth) { - _Frames.resize(__std_stacktrace_capture(static_cast(_Skip), - static_cast(_Max_depth), reinterpret_cast(_Frames.data()), &_Hash)); - } + basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Alloc) : _Frames(_Max_depth, _Alloc) {} _Frames_t _Frames; unsigned long _Hash = 0; diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 6b34839a92..b84b1e1f2e 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -139,10 +139,13 @@ namespace { clear_if_wrong_address(entry, address); if (!entry.is_line_valid) { - bool success = try_initialize() - && SymFromAddr(process_handle, reinterpret_cast(address), nullptr, &entry.info); + DWORD d = 0; + bool success = + try_initialize() + && SymGetLineFromAddr(process_handle, reinterpret_cast(address), &d, &entry.line); if (!success) { - entry.info.NameLen = 0; + entry.line.FileName = nullptr; + entry.line.LineNumber = 0; } entry.is_line_valid = true; } @@ -161,6 +164,9 @@ namespace { unsigned short __stdcall __std_stacktrace_capture( unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash) { +#ifdef _DEBUG + _FramesToSkip += 1; // compensate absense of tail call optimization here +#endif return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); } From 1e0b47cde214bc47ed368153f7d221f349f2fde5 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:08:42 +0200 Subject: [PATCH 003/131] feature, missing (c), pmr --- stl/inc/stacktrace | 6 +++++- stl/inc/yvals_core.h | 2 ++ stl/src/msvcp_stacktrace.def | 2 ++ .../test.compile.pass.cpp | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index ab840774d7..60cbf3364d 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -1,4 +1,4 @@ -// stack standard header +// stacktrace standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -279,6 +279,10 @@ basic_ostream& operator<<(basic_ostream& _Os, cons return _Os << to_string(_Fx); } +namespace pmr { + using stacktrace = basic_stacktrace>; +} + template <> struct hash : private hash { size_t operator()(const stacktrace_entry& _Val) const { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index bcd7886bbb..86727e68fb 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -283,6 +283,7 @@ // P0401R6 Providing Size Feedback In The Allocator Interface // P0448R4 // P0798R8 Monadic Operations For optional +// P0881R7 // P0943R6 Supporting C Atomics In C++ // P1048R1 is_scoped_enum // P1072R10 basic_string::resize_and_overwrite @@ -1413,6 +1414,7 @@ #endif // __cpp_lib_concepts #define __cpp_lib_spanstream 202106L +#define __cpp_lib_stacktrace 202011L #define __cpp_lib_stdatomic_h 202011L #define __cpp_lib_string_contains 202011L #define __cpp_lib_string_resize_and_overwrite 202110L diff --git a/stl/src/msvcp_stacktrace.def b/stl/src/msvcp_stacktrace.def index a804fd0dc4..bca7ae4907 100644 --- a/stl/src/msvcp_stacktrace.def +++ b/stl/src/msvcp_stacktrace.def @@ -1,3 +1,5 @@ +; Copyright (c) Microsoft Corporation. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception EXPORTS __std_stacktrace_capture diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 2379133b46..c09dfc3456 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1614,6 +1614,20 @@ STATIC_ASSERT(__cpp_lib_stdatomic_h == 202011L); #endif #endif +#if _HAS_CXX23 +#ifndef __cpp_lib_stacktrace +#error __cpp_lib_stacktrace is not defined +#elif __cpp_lib_stacktrace != 202011L +#error __cpp_lib_stacktrace is not 202011L +#else +STATIC_ASSERT(__cpp_lib_stacktrace == 202011L); +#endif +#else +#ifdef __cpp_lib_stacktrace +#error __cpp_lib_stacktrace is defined +#endif +#endif + #if _HAS_CXX23 #ifndef __cpp_lib_string_contains #error __cpp_lib_string_contains is not defined From 96ade42458396d0f5140e92ae9d82ec45f47e758 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:10:35 +0200 Subject: [PATCH 004/131] x86 build --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index b84b1e1f2e..610bdef0af 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -31,7 +31,7 @@ namespace { void* address = nullptr; bool is_description_valid = false; bool is_line_valid = false; - IMAGEHLP_LINE64 line = {sizeof(IMAGEHLP_LINE64)}; + IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE64)}; SYMBOL_INFO info = InitSymbolInfo(); wchar_t buffer[max_line_size]; }; From c480c553f88443cde9c704ebf088bf070e681f16 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:14:50 +0200 Subject: [PATCH 005/131] header! --- stl/CMakeLists.txt | 1 + stl/inc/__msvc_all_public_headers.hpp | 1 + stl/inc/header-units.json | 2 ++ .../P1502R1_standard_library_header_units/custom_format.py | 1 + .../tests/P1502R1_standard_library_header_units/custombuild.pl | 1 + tests/std/tests/P1502R1_standard_library_header_units/test.cpp | 1 + tests/std/tests/include_each_header_alone_matrix.lst | 1 + 7 files changed, 8 insertions(+) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 8e92693698..68eceef65f 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -185,6 +185,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/spanstream ${CMAKE_CURRENT_LIST_DIR}/inc/sstream ${CMAKE_CURRENT_LIST_DIR}/inc/stack + ${CMAKE_CURRENT_LIST_DIR}/inc/stacktrace ${CMAKE_CURRENT_LIST_DIR}/inc/stdatomic.h ${CMAKE_CURRENT_LIST_DIR}/inc/stdexcept ${CMAKE_CURRENT_LIST_DIR}/inc/stop_token diff --git a/stl/inc/__msvc_all_public_headers.hpp b/stl/inc/__msvc_all_public_headers.hpp index 8de1be161e..eed6744ec1 100644 --- a/stl/inc/__msvc_all_public_headers.hpp +++ b/stl/inc/__msvc_all_public_headers.hpp @@ -120,6 +120,7 @@ #include #include #include +#include #include #include #include diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json index e22b1ce80f..eee07ff0fd 100644 --- a/stl/inc/header-units.json +++ b/stl/inc/header-units.json @@ -1,4 +1,5 @@ // Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception { @@ -95,6 +96,7 @@ "spanstream", "sstream", "stack", + "stacktrace", "stdatomic.h", "stdexcept", "stop_token", diff --git a/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py b/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py index 7610705bb8..c8dff39c1d 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py +++ b/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py @@ -68,6 +68,7 @@ def getBuildSteps(self, test, litConfig, shared): 'spanstream', 'sstream', 'stack', + 'stacktrace', 'stdexcept', 'stop_token', 'streambuf', diff --git a/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl b/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl index 3e0497ce82..dcc8902587 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl +++ b/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl @@ -66,6 +66,7 @@ () "spanstream", "sstream", "stack", + "stacktrace", "stdexcept", "stop_token", "streambuf", diff --git a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp index f2dd1d14d4..d726fc31e5 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp +++ b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp @@ -68,6 +68,7 @@ import ; import ; import ; import ; +import ; import ; import ; import ; diff --git a/tests/std/tests/include_each_header_alone_matrix.lst b/tests/std/tests/include_each_header_alone_matrix.lst index 7c17b29dfd..ef2fa9038c 100644 --- a/tests/std/tests/include_each_header_alone_matrix.lst +++ b/tests/std/tests/include_each_header_alone_matrix.lst @@ -65,6 +65,7 @@ PM_CL="/DMEOW_HEADER=span" PM_CL="/DMEOW_HEADER=spanstream" PM_CL="/DMEOW_HEADER=sstream" PM_CL="/DMEOW_HEADER=stack" +PM_CL="/DMEOW_HEADER=stacktrace" PM_CL="/DMEOW_HEADER=stdatomic.h" PM_CL="/DMEOW_HEADER=stdexcept" PM_CL="/DMEOW_HEADER=stop_token" From b080877088337981c144638ce33d9cb06c8aa425 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:16:19 +0200 Subject: [PATCH 006/131] -copypasta comments --- stl/inc/stacktrace | 5 ----- 1 file changed, 5 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 60cbf3364d..74e275c857 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -33,8 +33,6 @@ unsigned short __stdcall __std_stacktrace_capture( [[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(void* _Address); _STD_BEGIN - -// 20.?.4, class stacktrace_entry class stacktrace_entry { public: using native_handle_type = void*; @@ -225,10 +223,8 @@ private: unsigned long _Hash = 0; }; -// basic_stacktrace typedef names using stacktrace = basic_stacktrace>; -// 20.?.6, non-member functions template void swap(basic_stacktrace& _Ax, basic_stacktrace& _Bx) noexcept(noexcept(_Ax.swap(_Bx))) { return _Ax.swap(_Bx); @@ -296,7 +292,6 @@ struct hash> { return _Val; } }; - _STD_END #pragma pop_macro("new") From ec9e855d4417b34a9207d8aa720861a92a9b96cc Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:20:58 +0200 Subject: [PATCH 007/131] Ugly Al --- stl/inc/stacktrace | 53 +++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 74e275c857..7074aafb6f 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -37,9 +37,9 @@ class stacktrace_entry { public: using native_handle_type = void*; - constexpr stacktrace_entry() noexcept = default; - constexpr stacktrace_entry(const stacktrace_entry& other) noexcept = default; - constexpr stacktrace_entry& operator=(const stacktrace_entry& other) noexcept = default; + constexpr stacktrace_entry() noexcept = default; + constexpr stacktrace_entry(const stacktrace_entry&) noexcept = default; + constexpr stacktrace_entry& operator=(const stacktrace_entry&) noexcept = default; ~stacktrace_entry() = default; @@ -63,11 +63,10 @@ public: return __std_stacktrace_source_line(_Address); } - [[nodiscard]] friend constexpr bool operator==( - const stacktrace_entry& x, const stacktrace_entry& y) noexcept = default; + [[nodiscard]] friend constexpr bool operator==(const stacktrace_entry&, const stacktrace_entry&) noexcept = default; [[nodiscard]] friend constexpr strong_ordering operator<=>( - const stacktrace_entry& x, const stacktrace_entry& y) noexcept = default; + const stacktrace_entry&, const stacktrace_entry&) noexcept = default; private: void* _Address = nullptr; @@ -125,7 +124,7 @@ public: : _Frames(move(_Other._Frames), _Alloc), _Hash(_Other._Hash) {} basic_stacktrace& operator=(const basic_stacktrace&) = default; - basic_stacktrace& operator=(basic_stacktrace&& other) noexcept(_Noex_move) = default; + basic_stacktrace& operator=(basic_stacktrace&&) noexcept(_Noex_move) = default; ~basic_stacktrace() = default; @@ -177,25 +176,25 @@ public: return _Frames.max_size(); } - const_reference operator[](size_type) const { - return _Frames[size_type]; + const_reference operator[](size_type _Sx) const { + return _Frames[_Sx]; } - const_reference at(size_type) const { - return _Frames.at(size_type); + const_reference at(size_type _Sx) const { + return _Frames.at(_Sx); } template - friend bool operator==(const basic_stacktrace& x, const basic_stacktrace<_Al2>& y) noexcept { - return _Hash == _Hash && _Frames == _Frames; + friend bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { + return _Lhs._Hash == _Rhs._Hash && _Lhs._Frames == _Rhs._Frames; } template - friend strong_ordering operator<=>(const basic_stacktrace& x, const basic_stacktrace<_Al2>& y) noexcept { - if (_Hash != _Hash) { - return _Hash <=> _Hash; + friend strong_ordering operator<=>(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { + if (Lhs._Hash != Rhs.Hash) { + return Lhs._Hash <=> Rhs._Hash; } else { - return _Frames <=> _Frames; + return Lhs._Frames <=> Rhs._Frames; } } @@ -225,8 +224,8 @@ private: using stacktrace = basic_stacktrace>; -template -void swap(basic_stacktrace& _Ax, basic_stacktrace& _Bx) noexcept(noexcept(_Ax.swap(_Bx))) { +template +void swap(basic_stacktrace<_Al>& _Ax, basic_stacktrace<_Al>& _Bx) noexcept(noexcept(_Ax.swap(_Bx))) { return _Ax.swap(_Bx); } @@ -243,15 +242,15 @@ string to_string(const stacktrace_entry& _Fx) { if (_Result.empty()) { _Result = move(_Desc); } else { - _Result = _Result + " " + _Desc; + _Result = _Result + ": " + _Desc; } } return _Result; } -template -string to_string(const basic_stacktrace& _St) { +template +string to_string(const basic_stacktrace<_Al>& _St) { string _Result; for (auto& _Entry : _St) { string _Entry_str = to_string(_Entry); @@ -270,8 +269,8 @@ basic_ostream& operator<<(basic_ostream& _Os, cons return _Os << to_string(_Fx); } -template -basic_ostream& operator<<(basic_ostream& _Os, const basic_stacktrace& _Fx) { +template +basic_ostream& operator<<(basic_ostream& _Os, const basic_stacktrace<_Al>& _Fx) { return _Os << to_string(_Fx); } @@ -286,9 +285,9 @@ struct hash : private hash { } }; -template -struct hash> { - size_t operator()(const basic_stacktrace& _Val) const { +template +struct hash> { + size_t operator()(const basic_stacktrace<_Al>& _Val) const { return _Val; } }; From 5575f9bef5a16a04fc5511b27ef11e5181148012 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:26:21 +0200 Subject: [PATCH 008/131] _STD move --- stl/inc/stacktrace | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 7074aafb6f..3381903c7f 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -121,7 +121,7 @@ public: : _Frames(_Other._Frames, _Alloc), _Hash(_Other._Hash) {} basic_stacktrace(basic_stacktrace&& _Other, const allocator_type& _Alloc) - : _Frames(move(_Other._Frames), _Alloc), _Hash(_Other._Hash) {} + : _Frames(_STD move(_Other._Frames), _Alloc), _Hash(_Other._Hash) {} basic_stacktrace& operator=(const basic_stacktrace&) = default; basic_stacktrace& operator=(basic_stacktrace&&) noexcept(_Noex_move) = default; @@ -240,7 +240,7 @@ string to_string(const stacktrace_entry& _Fx) { if (!_Desc.empty()) { if (_Result.empty()) { - _Result = move(_Desc); + _Result = _STD move(_Desc); } else { _Result = _Result + ": " + _Desc; } @@ -258,7 +258,7 @@ string to_string(const basic_stacktrace<_Al>& _St) { _Result.push_back('\n'); _Result.append(_Entry_str); } else { - _Result = move(_Entry_str); + _Result = _STD move(_Entry_str); } } return _Result; From ec470a570e84b924bf263a64be2aeb7e3b22ea25 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:26:33 +0200 Subject: [PATCH 009/131] right size --- stl/src/stacktrace.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 610bdef0af..fd9f20c1cd 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -12,7 +12,6 @@ #pragma comment(lib, "Dbghelp.lib") namespace { - static constexpr std::size_t max_line_size = 2000; static constexpr std::size_t max_file_size = 260; @@ -31,7 +30,7 @@ namespace { void* address = nullptr; bool is_description_valid = false; bool is_line_valid = false; - IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE64)}; + IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE)}; SYMBOL_INFO info = InitSymbolInfo(); wchar_t buffer[max_line_size]; }; From 1cb8b79e459d3eb8bb66606cbe4dc1e26fa47771 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:45:07 +0200 Subject: [PATCH 010/131] test pass --- stl/inc/stacktrace | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 3381903c7f..f81b3d5b5b 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -81,7 +81,7 @@ public: using value_type = stacktrace_entry; using const_reference = const value_type&; using reference = value_type&; - using const_iterator = _Frames_t::const_iterator; + using const_iterator = typename _Frames_t::const_iterator; using iterator = const_iterator; using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; @@ -191,10 +191,10 @@ public: template friend strong_ordering operator<=>(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { - if (Lhs._Hash != Rhs.Hash) { - return Lhs._Hash <=> Rhs._Hash; + if (_Lhs._Hash != _Rhs.Hash) { + return _Lhs._Hash <=> _Rhs._Hash; } else { - return Lhs._Frames <=> Rhs._Frames; + return _Lhs._Frames <=> _Rhs._Frames; } } @@ -211,8 +211,8 @@ public: private: static constexpr size_t _Max_frames = 0xFFFF; - bool _Noex_move = allocator_traits<_Al>::propagate_on_container_move_assignment::value - || allocator_traits<_Al>::is_always_equal::value; + static constexpr bool _Noex_move = allocator_traits<_Al>::propagate_on_container_move_assignment::value + || allocator_traits<_Al>::is_always_equal::value; struct _Internal_t {}; @@ -229,7 +229,7 @@ void swap(basic_stacktrace<_Al>& _Ax, basic_stacktrace<_Al>& _Bx) noexcept(noexc return _Ax.swap(_Bx); } -string to_string(const stacktrace_entry& _Fx) { +inline string to_string(const stacktrace_entry& _Fx) { string _Result; auto _Line = _Fx.source_line(); auto _Desc = _Fx.description(); From df9b1ba318605848688a81acab00deae92f75d90 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 20:54:07 +0200 Subject: [PATCH 011/131] -lines --- stl/inc/header-units.json | 1 - stl/src/stacktrace.cpp | 9 ++++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json index eee07ff0fd..cb08f53b39 100644 --- a/stl/inc/header-units.json +++ b/stl/inc/header-units.json @@ -1,5 +1,4 @@ // Copyright (c) Microsoft Corporation. -// Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception { diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index fd9f20c1cd..a206c2263d 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -80,7 +80,7 @@ namespace { std::string description(void* address) { auto& entry = hash_table_entry(address); - srw_lock_guard lock{mutex}; + srw_lock_guard lock{srw}; clear_if_wrong_address(entry, address); if (!entry.is_description_valid) { @@ -97,7 +97,7 @@ namespace { std::string source_file(void* address) { auto& entry = hash_table_entry(address); - srw_lock_guard lock{mutex}; + srw_lock_guard lock{srw}; initialize_line(entry, address); @@ -106,7 +106,7 @@ namespace { unsigned source_line(void* address) { auto& entry = hash_table_entry(address); - srw_lock_guard lock{mutex}; + srw_lock_guard lock{srw}; initialize_line(entry, address); @@ -150,8 +150,7 @@ namespace { } } - - SRWLOCK mutex = SRWLOCK_INIT; + SRWLOCK srw = SRWLOCK_INIT; HANDLE process_handle = nullptr; bool initialized = false; bool initialize_attepted = false; From 603e8d7b6c2011517ca818bf3d729f1e1dcb24fc Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 21:06:17 +0200 Subject: [PATCH 012/131] too few [[nodiscard]] --- stl/inc/stacktrace | 27 ++++++++++++++------------- stl/src/stacktrace.cpp | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index f81b3d5b5b..455ecf0e9f 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -25,7 +25,7 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -unsigned short __stdcall __std_stacktrace_capture( +[[nodiscard]] unsigned short __stdcall __std_stacktrace_capture( unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash); [[nodiscard]] _STD string __stdcall __std_stacktrace_description(void* _Address); @@ -168,29 +168,30 @@ public: return _Frames.empty(); } - size_type size() const noexcept { + [[nodiscard]] size_type size() const noexcept { return _Frames.size(); } - size_type max_size() const noexcept { + [[nodiscard]] size_type max_size() const noexcept { return _Frames.max_size(); } - const_reference operator[](size_type _Sx) const { + [[nodiscard]] const_reference operator[](size_type _Sx) const { return _Frames[_Sx]; } - const_reference at(size_type _Sx) const { + [[nodiscard]] const_reference at(size_type _Sx) const { return _Frames.at(_Sx); } template - friend bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { + [[nodiscard]] friend bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { return _Lhs._Hash == _Rhs._Hash && _Lhs._Frames == _Rhs._Frames; } template - friend strong_ordering operator<=>(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { + [[nodiscard]] friend strong_ordering operator<=>( + const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { if (_Lhs._Hash != _Rhs.Hash) { return _Lhs._Hash <=> _Rhs._Hash; } else { @@ -204,7 +205,7 @@ public: _STD swap(_Hash, _Other._Hash); } - unsigned long _Get_hash() const { + [[nodiscard]] unsigned long _Get_hash() const { return _Hash; } @@ -229,7 +230,7 @@ void swap(basic_stacktrace<_Al>& _Ax, basic_stacktrace<_Al>& _Bx) noexcept(noexc return _Ax.swap(_Bx); } -inline string to_string(const stacktrace_entry& _Fx) { +[[nodiscard]] inline string to_string(const stacktrace_entry& _Fx) { string _Result; auto _Line = _Fx.source_line(); auto _Desc = _Fx.description(); @@ -250,7 +251,7 @@ inline string to_string(const stacktrace_entry& _Fx) { } template -string to_string(const basic_stacktrace<_Al>& _St) { +[[nodiscard]] string to_string(const basic_stacktrace<_Al>& _St) { string _Result; for (auto& _Entry : _St) { string _Entry_str = to_string(_Entry); @@ -280,15 +281,15 @@ namespace pmr { template <> struct hash : private hash { - size_t operator()(const stacktrace_entry& _Val) const { + [[nodiscard]] size_t operator()(const stacktrace_entry& _Val) const { return hash::operator()(_Val.native_handle()); } }; template struct hash> { - size_t operator()(const basic_stacktrace<_Al>& _Val) const { - return _Val; + [[nodiscard]] size_t operator()(const basic_stacktrace<_Al>& _Val) const { + return _Val._Get_hash(); } }; _STD_END diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index a206c2263d..e2014379ec 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -160,7 +160,7 @@ namespace { } // namespace -unsigned short __stdcall __std_stacktrace_capture( +[[nodiscard]] unsigned short __stdcall __std_stacktrace_capture( unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash) { #ifdef _DEBUG _FramesToSkip += 1; // compensate absense of tail call optimization here From 115229f0f15440547fc88cd4b839e8171fb50ca5 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 21:39:55 +0200 Subject: [PATCH 013/131] hash hash --- stl/inc/stacktrace | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 455ecf0e9f..4428413a17 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -14,8 +14,8 @@ #else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv #include -#include #include +#include #include #pragma pack(push, _CRT_PACKING) @@ -205,7 +205,7 @@ public: _STD swap(_Hash, _Other._Hash); } - [[nodiscard]] unsigned long _Get_hash() const { + [[nodiscard]] unsigned long _Get_hash() const noexcept { return _Hash; } @@ -280,15 +280,21 @@ namespace pmr { } template <> -struct hash : private hash { - [[nodiscard]] size_t operator()(const stacktrace_entry& _Val) const { - return hash::operator()(_Val.native_handle()); +struct hash { + _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef stacktrace_entry _ARGUMENT_TYPE_NAME; + _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; + + [[nodiscard]] size_t operator()(const stacktrace_entry& _Val) const noexcept { + return _Hash_representation(_Val.native_handle()); } }; template struct hash> { - [[nodiscard]] size_t operator()(const basic_stacktrace<_Al>& _Val) const { + _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef basic_stacktrace<_Al> _ARGUMENT_TYPE_NAME; + _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; + + [[nodiscard]] size_t operator()(const basic_stacktrace<_Al>& _Val) const noexcept { return _Val._Get_hash(); } }; From ab3d65b89493316ca8b030f841c6630d0231fafe Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 21:41:16 +0200 Subject: [PATCH 014/131] no, removed --- stl/inc/stacktrace | 6 ------ 1 file changed, 6 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 4428413a17..0b4b8baad9 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -281,9 +281,6 @@ namespace pmr { template <> struct hash { - _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef stacktrace_entry _ARGUMENT_TYPE_NAME; - _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; - [[nodiscard]] size_t operator()(const stacktrace_entry& _Val) const noexcept { return _Hash_representation(_Val.native_handle()); } @@ -291,9 +288,6 @@ struct hash { template struct hash> { - _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef basic_stacktrace<_Al> _ARGUMENT_TYPE_NAME; - _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; - [[nodiscard]] size_t operator()(const basic_stacktrace<_Al>& _Val) const noexcept { return _Val._Get_hash(); } From a475f02f59afdaf0b5b76b409d5c2eaddafb20f2 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 21:57:11 +0200 Subject: [PATCH 015/131] it is overspecified to me! --- stl/inc/stacktrace | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 0b4b8baad9..92ade9e6ba 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -192,11 +192,12 @@ public: template [[nodiscard]] friend strong_ordering operator<=>( const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { - if (_Lhs._Hash != _Rhs.Hash) { - return _Lhs._Hash <=> _Rhs._Hash; - } else { - return _Lhs._Frames <=> _Rhs._Frames; + const auto _Result = _Lhs._Frames._Size <=> _Rhs._Frames._Size; + if (_Result != strong_ordering::equal) { + return _Result; } + + return _Lhs._Frames <=> _Rhs._Frames; } void swap(basic_stacktrace& _Other) noexcept( From a7e2edd582377ccca272cb3d9cf4e10674f9c4a4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 21:57:35 +0200 Subject: [PATCH 016/131] size --- stl/inc/stacktrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 92ade9e6ba..1a041c2e6b 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -192,7 +192,7 @@ public: template [[nodiscard]] friend strong_ordering operator<=>( const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { - const auto _Result = _Lhs._Frames._Size <=> _Rhs._Frames._Size; + const auto _Result = _Lhs._Frames.size() <=> _Rhs._Frames.size(); if (_Result != strong_ordering::equal) { return _Result; } From f58f4765b433c2ea5f9df0b9bbb4cb3934f242b5 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 22:16:31 +0200 Subject: [PATCH 017/131] conventions --- stl/src/stacktrace.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index e2014379ec..542ec1834f 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -13,13 +13,12 @@ namespace { static constexpr std::size_t max_line_size = 2000; - static constexpr std::size_t max_file_size = 260; static constexpr std::size_t table_size_power_of_two_factor = 10; static constexpr std::size_t table_size = 1 << table_size_power_of_two_factor; - static constexpr SYMBOL_INFO InitSymbolInfo() { + static constexpr SYMBOL_INFO init_symbol_info() { SYMBOL_INFO result = {}; result.SizeOfStruct = sizeof(SYMBOL_INFO); result.MaxNameLen = max_line_size; @@ -31,7 +30,7 @@ namespace { bool is_description_valid = false; bool is_line_valid = false; IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE)}; - SYMBOL_INFO info = InitSymbolInfo(); + SYMBOL_INFO info = init_symbol_info(); wchar_t buffer[max_line_size]; }; @@ -64,7 +63,7 @@ namespace { } if (process_handle) { - ::CloseHandle(process_handle); + CloseHandle(process_handle); } } From 20364f68442050bad0359b766fdf41fc6d0136aa Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 23 Jan 2022 23:18:36 +0200 Subject: [PATCH 018/131] Don't pass nullptr to string ctor --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 542ec1834f..2142852446 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -100,7 +100,7 @@ namespace { initialize_line(entry, address); - return entry.line.FileName; + return entry.line.FileName ? entry.line.FileName : ""; } unsigned source_line(void* address) { From a561b5386e779d4c2f8dcc6b22797a770fd42b07 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 11:47:43 +0200 Subject: [PATCH 019/131] strengthen --- stl/inc/stacktrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 1a041c2e6b..26a235fec8 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -176,7 +176,7 @@ public: return _Frames.max_size(); } - [[nodiscard]] const_reference operator[](size_type _Sx) const { + [[nodiscard]] const_reference operator[](size_type _Sx) const noexcept /* strengthened */ { return _Frames[_Sx]; } From 9ddfb94f1b0b21043e63264c00af84e60524e432 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 12:28:41 +0200 Subject: [PATCH 020/131] typo --- stl/src/stacktrace.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 2142852446..f8cd4d4778 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -114,12 +114,12 @@ namespace { private: bool try_initialize() { - if (!initialize_attepted) { + if (!initialize_attempted) { initialized = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &process_handle, PROCESS_QUERY_INFORMATION, false, 0) && SymInitialize(process_handle, nullptr, true); - initialize_attepted = true; + initialize_attempted = true; } return initialized; @@ -149,10 +149,10 @@ namespace { } } - SRWLOCK srw = SRWLOCK_INIT; - HANDLE process_handle = nullptr; - bool initialized = false; - bool initialize_attepted = false; + SRWLOCK srw = SRWLOCK_INIT; + HANDLE process_handle = nullptr; + bool initialized = false; + bool initialize_attempted = false; }; static stacktrace_global_data_t stacktrace_global_data; From 59ee7fab1d399828dc9f5707e368dd23befe2308 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 13:10:03 +0200 Subject: [PATCH 021/131] save displacement --- stl/src/stacktrace.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index f8cd4d4778..22e9866695 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include @@ -30,6 +31,7 @@ namespace { bool is_description_valid = false; bool is_line_valid = false; IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE)}; + DWORD displacement = 0; SYMBOL_INFO info = init_symbol_info(); wchar_t buffer[max_line_size]; }; @@ -137,13 +139,13 @@ namespace { clear_if_wrong_address(entry, address); if (!entry.is_line_valid) { - DWORD d = 0; - bool success = - try_initialize() - && SymGetLineFromAddr(process_handle, reinterpret_cast(address), &d, &entry.line); + bool success = try_initialize() + && SymGetLineFromAddr( + process_handle, reinterpret_cast(address), &entry.displacement, &entry.line); if (!success) { entry.line.FileName = nullptr; entry.line.LineNumber = 0; + entry.displacement = 0; } entry.is_line_valid = true; } From 8090d3d8f34e163733d262ea09252c58af6d8128 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 15:51:07 +0200 Subject: [PATCH 022/131] cache only the last address and no more --- stl/src/stacktrace.cpp | 98 +++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 22e9866695..bde1240e42 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -15,29 +15,6 @@ namespace { static constexpr std::size_t max_line_size = 2000; - static constexpr std::size_t table_size_power_of_two_factor = 10; - - static constexpr std::size_t table_size = 1 << table_size_power_of_two_factor; - - static constexpr SYMBOL_INFO init_symbol_info() { - SYMBOL_INFO result = {}; - result.SizeOfStruct = sizeof(SYMBOL_INFO); - result.MaxNameLen = max_line_size; - return result; - } - - struct stacktrace_address_table_entry_t { - void* address = nullptr; - bool is_description_valid = false; - bool is_line_valid = false; - IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE)}; - DWORD displacement = 0; - SYMBOL_INFO info = init_symbol_info(); - wchar_t buffer[max_line_size]; - }; - - static stacktrace_address_table_entry_t stacktrace_address_table[table_size]; - class _NODISCARD srw_lock_guard { public: explicit srw_lock_guard(SRWLOCK& locked_) noexcept : locked(&locked_) { @@ -57,7 +34,7 @@ namespace { class stacktrace_global_data_t { public: - stacktrace_global_data_t() = default; + constexpr stacktrace_global_data_t() = default; ~stacktrace_global_data_t() { if (initialized) { @@ -72,46 +49,37 @@ namespace { stacktrace_global_data_t(const stacktrace_global_data_t&) = delete; stacktrace_global_data_t& operator=(const stacktrace_global_data_t) = delete; - static stacktrace_address_table_entry_t& hash_table_entry(void* address) { - auto index = reinterpret_cast(address); - index ^= index >> table_size_power_of_two_factor; - index &= (1 << table_size_power_of_two_factor) - 1; - return stacktrace_address_table[index]; - } std::string description(void* address) { - auto& entry = hash_table_entry(address); srw_lock_guard lock{srw}; - clear_if_wrong_address(entry, address); + clear_if_wrong_address(address); - if (!entry.is_description_valid) { + if (!is_description_valid) { bool success = try_initialize() - && SymFromAddr(process_handle, reinterpret_cast(address), nullptr, &entry.info); + && SymFromAddr(process_handle, reinterpret_cast(address), nullptr, &info); if (!success) { - entry.info.NameLen = 0; + info.NameLen = 0; } - entry.is_description_valid = true; + is_description_valid = true; } - return std::string(entry.info.Name, entry.info.NameLen); + return std::string(info.Name, info.NameLen); } std::string source_file(void* address) { - auto& entry = hash_table_entry(address); srw_lock_guard lock{srw}; - initialize_line(entry, address); + initialize_line(address); - return entry.line.FileName ? entry.line.FileName : ""; + return line.FileName ? line.FileName : ""; } unsigned source_line(void* address) { - auto& entry = hash_table_entry(address); srw_lock_guard lock{srw}; - initialize_line(entry, address); + initialize_line(address); - return entry.line.LineNumber; + return line.LineNumber; } private: @@ -127,34 +95,48 @@ namespace { return initialized; } - void clear_if_wrong_address(stacktrace_address_table_entry_t& entry, void* address) { - if (entry.address != address) { - entry.is_description_valid = false; - entry.is_line_valid = false; - entry.address = address; + void clear_if_wrong_address(void* address) { + if (last_address != address) { + is_description_valid = false; + is_line_valid = false; + last_address = address; } } - void initialize_line(stacktrace_address_table_entry_t& entry, void* address) { - clear_if_wrong_address(entry, address); + void initialize_line(void* address) { + clear_if_wrong_address(address); - if (!entry.is_line_valid) { - bool success = try_initialize() - && SymGetLineFromAddr( - process_handle, reinterpret_cast(address), &entry.displacement, &entry.line); + if (!is_line_valid) { + bool success = + try_initialize() + && SymGetLineFromAddr(process_handle, reinterpret_cast(address), &displacement, &line); if (!success) { - entry.line.FileName = nullptr; - entry.line.LineNumber = 0; - entry.displacement = 0; + line.FileName = nullptr; + line.LineNumber = 0; + displacement = 0; } - entry.is_line_valid = true; + is_line_valid = true; } } + static constexpr SYMBOL_INFO init_symbol_info() { + SYMBOL_INFO result = {}; + result.SizeOfStruct = sizeof(SYMBOL_INFO); + result.MaxNameLen = max_line_size; + return result; + } + SRWLOCK srw = SRWLOCK_INIT; HANDLE process_handle = nullptr; bool initialized = false; bool initialize_attempted = false; + void* last_address = nullptr; + bool is_description_valid = false; + bool is_line_valid = false; + IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE)}; + DWORD displacement = 0; + SYMBOL_INFO info = init_symbol_info(); + wchar_t buffer[max_line_size]; }; static stacktrace_global_data_t stacktrace_global_data; From 7fb6f858d4f4c24322e131194941f6e110d61cd1 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 15:53:42 +0200 Subject: [PATCH 023/131] not using format yet --- stl/src/stacktrace.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index bde1240e42..a27c48fc0b 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include #include #include From 98a07935253ff2ae6d66fa469b8833613d14faf1 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 16:50:15 +0200 Subject: [PATCH 024/131] move string conversion to .cpp --- stl/inc/stacktrace | 43 ++++++++-------------------- stl/src/msvcp_stacktrace.def | 2 ++ stl/src/stacktrace.cpp | 54 ++++++++++++++++++++++++++++++------ 3 files changed, 59 insertions(+), 40 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 26a235fec8..babaf44aee 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -28,9 +28,11 @@ _STL_DISABLE_CLANG_WARNINGS [[nodiscard]] unsigned short __stdcall __std_stacktrace_capture( unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash); -[[nodiscard]] _STD string __stdcall __std_stacktrace_description(void* _Address); -[[nodiscard]] _STD string __stdcall __std_stacktrace_source_file(void* _Address); -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(void* _Address); +[[nodiscard]] _STD string __stdcall __std_stacktrace_address_to_string(const void* _Address); +[[nodiscard]] _STD string __stdcall __std_stacktrace_description(const void* _Address); +[[nodiscard]] _STD string __stdcall __std_stacktrace_source_file(const void* _Address); +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address); +[[nodiscard]] _STD string __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size); _STD_BEGIN class stacktrace_entry { @@ -210,6 +212,11 @@ public: return _Hash; } + [[nodiscard]] const void* _Data() const noexcept { + return _Frames.data(); + } + + private: static constexpr size_t _Max_frames = 0xFFFF; @@ -232,38 +239,12 @@ void swap(basic_stacktrace<_Al>& _Ax, basic_stacktrace<_Al>& _Bx) noexcept(noexc } [[nodiscard]] inline string to_string(const stacktrace_entry& _Fx) { - string _Result; - auto _Line = _Fx.source_line(); - auto _Desc = _Fx.description(); - - if (_Line != 0) { - _Result = _Fx.source_file() + "(" + to_string(_Line) + ")"; - } - - if (!_Desc.empty()) { - if (_Result.empty()) { - _Result = _STD move(_Desc); - } else { - _Result = _Result + ": " + _Desc; - } - } - - return _Result; + return __std_stacktrace_address_to_string(_Fx.native_handle()); } template [[nodiscard]] string to_string(const basic_stacktrace<_Al>& _St) { - string _Result; - for (auto& _Entry : _St) { - string _Entry_str = to_string(_Entry); - if (!_Result.empty()) { - _Result.push_back('\n'); - _Result.append(_Entry_str); - } else { - _Result = _STD move(_Entry_str); - } - } - return _Result; + return __std_stacktrace_to_string(_St._Data(), _St.size()); } template diff --git a/stl/src/msvcp_stacktrace.def b/stl/src/msvcp_stacktrace.def index bca7ae4907..98bf67a66e 100644 --- a/stl/src/msvcp_stacktrace.def +++ b/stl/src/msvcp_stacktrace.def @@ -2,7 +2,9 @@ ; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception EXPORTS + __std_stacktrace_address_to_string __std_stacktrace_capture __std_stacktrace_description __std_stacktrace_source_file __std_stacktrace_source_line + __std_stacktrace_to_string diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index a27c48fc0b..edb395141a 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include @@ -49,7 +50,7 @@ namespace { stacktrace_global_data_t& operator=(const stacktrace_global_data_t) = delete; - std::string description(void* address) { + std::string description(const void* const address) { srw_lock_guard lock{srw}; clear_if_wrong_address(address); @@ -65,7 +66,7 @@ namespace { return std::string(info.Name, info.NameLen); } - std::string source_file(void* address) { + std::string source_file(const void* const address) { srw_lock_guard lock{srw}; initialize_line(address); @@ -73,7 +74,7 @@ namespace { return line.FileName ? line.FileName : ""; } - unsigned source_line(void* address) { + unsigned source_line(const void* const address) { srw_lock_guard lock{srw}; initialize_line(address); @@ -94,7 +95,7 @@ namespace { return initialized; } - void clear_if_wrong_address(void* address) { + void clear_if_wrong_address(const void* const address) { if (last_address != address) { is_description_valid = false; is_line_valid = false; @@ -102,7 +103,7 @@ namespace { } } - void initialize_line(void* address) { + void initialize_line(const void* const address) { clear_if_wrong_address(address); if (!is_line_valid) { @@ -129,7 +130,7 @@ namespace { HANDLE process_handle = nullptr; bool initialized = false; bool initialize_attempted = false; - void* last_address = nullptr; + const void* last_address = nullptr; bool is_description_valid = false; bool is_line_valid = false; IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE)}; @@ -150,14 +151,49 @@ namespace { return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); } -[[nodiscard]] _STD string __stdcall __std_stacktrace_description(void* _Address) { +[[nodiscard]] std::string __stdcall __std_stacktrace_description(const void* _Address) { return stacktrace_global_data.description(_Address); } -[[nodiscard]] _STD string __stdcall __std_stacktrace_source_file(void* _Address) { +[[nodiscard]] std::string __stdcall __std_stacktrace_source_file(const void* _Address) { return stacktrace_global_data.source_file(_Address); } -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(void* _Address) { +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) { return stacktrace_global_data.source_line(_Address); } + +[[nodiscard]] std::string __stdcall __std_stacktrace_address_to_string(const void* _Address) { + std::string result; + auto line = __std_stacktrace_source_line(_Address); + auto desc = __std_stacktrace_description(_Address); + + if (line != 0) { + result = std::format("{}({})", _Address, line); + } + + if (!desc.empty()) { + if (result.empty()) { + result = std::move(desc); + } else { + result = std::format("{}: {}", result, desc); + } + } + + return result; +} + +[[nodiscard]] std::string __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size) { + auto data = reinterpret_cast(_Addresses); + std::string result; + for (std::size_t i = 0; i != _Size; ++i) { + auto str = __std_stacktrace_address_to_string(data[i]); + if (!result.empty()) { + result.push_back('\n'); + result.append(str); + } else { + result = std::move(str); + } + } + return result; +} From bca36f31eaac24a85cc73464e6665396d3a75dbe Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 16:54:44 +0200 Subject: [PATCH 025/131] file --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index edb395141a..f169d16907 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -169,7 +169,7 @@ namespace { auto desc = __std_stacktrace_description(_Address); if (line != 0) { - result = std::format("{}({})", _Address, line); + result = std::format("{}({})", __std_stacktrace_source_file(_Address), line); } if (!desc.empty()) { From 7562e130d2841ebab96dfafd7e7b2a09106c51f3 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 18:59:57 +0200 Subject: [PATCH 026/131] Add module/offset --- stl/CMakeLists.txt | 2 +- stl/src/stacktrace.cpp | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 68eceef65f..32ac7a08c8 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -530,7 +530,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_stacktrace_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp${D_SUFFIX}_stacktrace SHARED "${CMAKE_CURRENT_LIST_DIR}/src/msvcp_stacktrace.def") - target_link_libraries(msvcp${D_SUFFIX}_stacktrace PRIVATE msvcp${D_SUFFIX}_stacktrace_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "Dbghelp.lib") + target_link_libraries(msvcp${D_SUFFIX}_stacktrace PRIVATE msvcp${D_SUFFIX}_stacktrace_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "Dbghelp.lib" "Shlwapi.lib") set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_stacktrace${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_stacktrace${VCLIBS_SUFFIX}") diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index f169d16907..0f58b4f2e5 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -6,11 +6,13 @@ #include // clang-format off +#include #include #include // clang-format on #pragma comment(lib, "Dbghelp.lib") +#pragma comment(lib, "Shlwapi.lib") namespace { static constexpr std::size_t max_line_size = 2000; @@ -57,13 +59,39 @@ namespace { if (!is_description_valid) { bool success = try_initialize() && SymFromAddr(process_handle, reinterpret_cast(address), nullptr, &info); - if (!success) { - info.NameLen = 0; + + if (success) { + function_address.clear(); + function_name = std::string_view(info.Name, info.NameLen); + offset = reinterpret_cast(address) - static_cast(info.Address); + } else { + function_address = std::format("{}", address); + function_name = function_address; + offset = 0; } + + if (!GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(address), &module_handle)) { + module_handle = nullptr; + } + + if (module_handle) { + GetModuleFileNameA(module_handle, module_path, MAX_PATH); + module_name = PathFindFileNameA(module_path); + } else { + module_name = ""; + } + is_description_valid = true; } - return std::string(info.Name, info.NameLen); + if (offset > 0) { + return std::format("{}!{}+{:#x}", module_name, function_name, offset); + + } else { + return std::format("{}!{}", module_name, function_name); + } } std::string source_file(const void* const address) { @@ -131,12 +159,18 @@ namespace { bool initialized = false; bool initialize_attempted = false; const void* last_address = nullptr; + HMODULE module_handle = nullptr; bool is_description_valid = false; bool is_line_valid = false; IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE)}; DWORD displacement = 0; + ptrdiff_t offset = 0; SYMBOL_INFO info = init_symbol_info(); - wchar_t buffer[max_line_size]; + char buffer[max_line_size]; + char module_path[MAX_PATH]; + const char* module_name = nullptr; + std::string_view function_name; + std::string function_address; }; static stacktrace_global_data_t stacktrace_global_data; From 1de504d71068ed78dd2e243524bb2f1a25a02953 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 19:00:30 +0200 Subject: [PATCH 027/131] Update stl/src/stacktrace.cpp Co-authored-by: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> --- stl/src/stacktrace.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 0f58b4f2e5..9ce83418fd 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -202,15 +202,11 @@ namespace { auto line = __std_stacktrace_source_line(_Address); auto desc = __std_stacktrace_description(_Address); - if (line != 0) { - result = std::format("{}({})", __std_stacktrace_source_file(_Address), line); - } - if (!desc.empty()) { - if (result.empty()) { - result = std::move(desc); + if (line == 0) { + return desc; } else { - result = std::format("{}: {}", result, desc); + return std::format("{}({}): {}", __std_stacktrace_source_file(_Address), line, desc); } } From dfbf80abdcd0b6f15496c56f692d95dd47c22905 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 24 Jan 2022 19:17:18 +0200 Subject: [PATCH 028/131] save on locks --- stl/src/stacktrace.cpp | 51 ++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 9ce83418fd..a4c0e5cb88 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -52,8 +52,7 @@ namespace { stacktrace_global_data_t& operator=(const stacktrace_global_data_t) = delete; - std::string description(const void* const address) { - srw_lock_guard lock{srw}; + [[nodiscard]] std::string description(const void* const address) { clear_if_wrong_address(address); if (!is_description_valid) { @@ -94,22 +93,31 @@ namespace { } } - std::string source_file(const void* const address) { - srw_lock_guard lock{srw}; - + [[nodiscard]] std::string source_file(const void* const address) { initialize_line(address); return line.FileName ? line.FileName : ""; } - unsigned source_line(const void* const address) { - srw_lock_guard lock{srw}; - + [[nodiscard]] unsigned source_line(const void* const address) { initialize_line(address); return line.LineNumber; } + [[nodiscard]] std::string address_to_string(const void* _Address) { + + auto cur_line = source_line(_Address); + auto cur_desc = description(_Address); + + if (cur_line == 0) { + return cur_desc; + } else { + return std::format("{}({}): {}", source_file(_Address), cur_line, cur_desc); + } + } + + private: bool try_initialize() { if (!initialize_attempted) { @@ -154,7 +162,6 @@ namespace { return result; } - SRWLOCK srw = SRWLOCK_INIT; HANDLE process_handle = nullptr; bool initialized = false; bool initialize_attempted = false; @@ -173,7 +180,10 @@ namespace { std::string function_address; }; - static stacktrace_global_data_t stacktrace_global_data; + stacktrace_global_data_t stacktrace_global_data; + + SRWLOCK srw = SRWLOCK_INIT; + } // namespace @@ -186,38 +196,31 @@ namespace { } [[nodiscard]] std::string __stdcall __std_stacktrace_description(const void* _Address) { + srw_lock_guard lock{srw}; return stacktrace_global_data.description(_Address); } [[nodiscard]] std::string __stdcall __std_stacktrace_source_file(const void* _Address) { + srw_lock_guard lock{srw}; return stacktrace_global_data.source_file(_Address); } [[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) { + srw_lock_guard lock{srw}; return stacktrace_global_data.source_line(_Address); } [[nodiscard]] std::string __stdcall __std_stacktrace_address_to_string(const void* _Address) { - std::string result; - auto line = __std_stacktrace_source_line(_Address); - auto desc = __std_stacktrace_description(_Address); - - if (!desc.empty()) { - if (line == 0) { - return desc; - } else { - return std::format("{}({}): {}", __std_stacktrace_source_file(_Address), line, desc); - } - } - - return result; + srw_lock_guard lock{srw}; + return stacktrace_global_data.address_to_string(_Address); } [[nodiscard]] std::string __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size) { + srw_lock_guard lock{srw}; auto data = reinterpret_cast(_Addresses); std::string result; for (std::size_t i = 0; i != _Size; ++i) { - auto str = __std_stacktrace_address_to_string(data[i]); + auto str = stacktrace_global_data.address_to_string(data[i]); if (!result.empty()) { result.push_back('\n'); result.append(str); From 0024cbe3fee95cc40d9829738fc892575e8056fe Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 26 Jan 2022 12:15:55 +0200 Subject: [PATCH 029/131] MAX_SYM_NAME --- stl/src/stacktrace.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index a4c0e5cb88..f2c13848a0 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -15,8 +15,6 @@ #pragma comment(lib, "Shlwapi.lib") namespace { - static constexpr std::size_t max_line_size = 2000; - class _NODISCARD srw_lock_guard { public: explicit srw_lock_guard(SRWLOCK& locked_) noexcept : locked(&locked_) { @@ -158,7 +156,7 @@ namespace { static constexpr SYMBOL_INFO init_symbol_info() { SYMBOL_INFO result = {}; result.SizeOfStruct = sizeof(SYMBOL_INFO); - result.MaxNameLen = max_line_size; + result.MaxNameLen = MAX_SYM_NAME; return result; } @@ -173,7 +171,7 @@ namespace { DWORD displacement = 0; ptrdiff_t offset = 0; SYMBOL_INFO info = init_symbol_info(); - char buffer[max_line_size]; + char buffer[MAX_SYM_NAME]; char module_path[MAX_PATH]; const char* module_name = nullptr; std::string_view function_name; From b18cb8105a562db3d1c1e2e7ea528d5466bf63f1 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 26 Jan 2022 14:02:31 +0200 Subject: [PATCH 030/131] Phoenix --- stl/src/stacktrace.cpp | 46 ++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index f2c13848a0..17ffe7220d 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -36,16 +36,6 @@ namespace { public: constexpr stacktrace_global_data_t() = default; - ~stacktrace_global_data_t() { - if (initialized) { - SymCleanup(process_handle); - } - - if (process_handle) { - CloseHandle(process_handle); - } - } - stacktrace_global_data_t(const stacktrace_global_data_t&) = delete; stacktrace_global_data_t& operator=(const stacktrace_global_data_t) = delete; @@ -117,17 +107,7 @@ namespace { private: - bool try_initialize() { - if (!initialize_attempted) { - initialized = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), - &process_handle, PROCESS_QUERY_INFORMATION, false, 0) - && SymInitialize(process_handle, nullptr, true); - - initialize_attempted = true; - } - - return initialized; - } + bool try_initialize(); void clear_if_wrong_address(const void* const address) { if (last_address != address) { @@ -179,9 +159,31 @@ namespace { }; stacktrace_global_data_t stacktrace_global_data; - SRWLOCK srw = SRWLOCK_INIT; + bool stacktrace_global_data_t::try_initialize() { + if (!initialize_attempted) { + initialized = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), + &process_handle, PROCESS_QUERY_INFORMATION, false, 0) + && SymInitialize(process_handle, nullptr, true); + + atexit([] { + if (stacktrace_global_data.initialized) { + SymCleanup(stacktrace_global_data.process_handle); + } + + if (stacktrace_global_data.process_handle) { + CloseHandle(stacktrace_global_data.process_handle); + } + stacktrace_global_data.initialize_attempted = false; + }); + + initialize_attempted = true; + } + + return initialized; + } + } // namespace From 8326f747400d106300967998ebdcbbc68b395042 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 3 Feb 2022 17:35:53 +0200 Subject: [PATCH 031/131] switch to --- stl/CMakeLists.txt | 2 +- stl/src/stacktrace.cpp | 161 +++++++++++++++++++++-------------------- 2 files changed, 85 insertions(+), 78 deletions(-) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 32ac7a08c8..4072f6c868 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -530,7 +530,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_stacktrace_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp${D_SUFFIX}_stacktrace SHARED "${CMAKE_CURRENT_LIST_DIR}/src/msvcp_stacktrace.def") - target_link_libraries(msvcp${D_SUFFIX}_stacktrace PRIVATE msvcp${D_SUFFIX}_stacktrace_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "Dbghelp.lib" "Shlwapi.lib") + target_link_libraries(msvcp${D_SUFFIX}_stacktrace PRIVATE msvcp${D_SUFFIX}_stacktrace_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_stacktrace${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_stacktrace${VCLIBS_SUFFIX}") diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 17ffe7220d..1434e7db81 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -2,19 +2,23 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include #include // clang-format off -#include -#include -#include +#include // should be before any header that includes +#include // clang-format on -#pragma comment(lib, "Dbghelp.lib") -#pragma comment(lib, "Shlwapi.lib") - namespace { + + struct com_release_t { + void operator()(auto* p) { + p->Release(); + } + }; + class _NODISCARD srw_lock_guard { public: explicit srw_lock_guard(SRWLOCK& locked_) noexcept : locked(&locked_) { @@ -34,63 +38,47 @@ namespace { class stacktrace_global_data_t { public: - constexpr stacktrace_global_data_t() = default; + constexpr stacktrace_global_data_t() noexcept = default; + constexpr ~stacktrace_global_data_t() = default; stacktrace_global_data_t(const stacktrace_global_data_t&) = delete; stacktrace_global_data_t& operator=(const stacktrace_global_data_t) = delete; - [[nodiscard]] std::string description(const void* const address) { clear_if_wrong_address(address); if (!is_description_valid) { bool success = try_initialize() - && SymFromAddr(process_handle, reinterpret_cast(address), nullptr, &info); - - if (success) { - function_address.clear(); - function_name = std::string_view(info.Name, info.NameLen); - offset = reinterpret_cast(address) - static_cast(info.Address); - } else { - function_address = std::format("{}", address); - function_name = function_address; - offset = 0; - } + && SUCCEEDED(debug_symbols->GetNameByOffset(reinterpret_cast(address), buffer, + static_cast(std::size(buffer)), &buffer_size, &symbol_displacement)); - if (!GetModuleHandleExW( - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - reinterpret_cast(address), &module_handle)) { - module_handle = nullptr; - } - - if (module_handle) { - GetModuleFileNameA(module_handle, module_path, MAX_PATH); - module_name = PathFindFileNameA(module_path); - } else { - module_name = ""; + if (!success) { + buffer_size = + static_cast(std::format_to_n(buffer, std::size(buffer), "{}", address).out - buffer); + symbol_displacement = 0; } is_description_valid = true; } - if (offset > 0) { - return std::format("{}!{}+{:#x}", module_name, function_name, offset); - + if (symbol_displacement != 0) { + return std::format( + "{}+{:#x}", std::string_view(buffer, buffer_size), symbol_displacement); } else { - return std::format("{}!{}", module_name, function_name); + return std::string(std::string_view(buffer, buffer_size)); } } [[nodiscard]] std::string source_file(const void* const address) { initialize_line(address); - return line.FileName ? line.FileName : ""; + return std::string(std::string_view(file_name, file_name_size)); } [[nodiscard]] unsigned source_line(const void* const address) { initialize_line(address); - return line.LineNumber; + return line; } [[nodiscard]] std::string address_to_string(const void* _Address) { @@ -123,39 +111,33 @@ namespace { if (!is_line_valid) { bool success = try_initialize() - && SymGetLineFromAddr(process_handle, reinterpret_cast(address), &displacement, &line); + && SUCCEEDED(debug_symbols->GetLineByOffset(reinterpret_cast(address), &line, file_name, + static_cast(std::size(file_name)), &file_name_size, &line_displacement)); if (!success) { - line.FileName = nullptr; - line.LineNumber = 0; - displacement = 0; + line = 0; + file_name_size = 0; + line_displacement = 0; } is_line_valid = true; } } - static constexpr SYMBOL_INFO init_symbol_info() { - SYMBOL_INFO result = {}; - result.SizeOfStruct = sizeof(SYMBOL_INFO); - result.MaxNameLen = MAX_SYM_NAME; - return result; - } - - HANDLE process_handle = nullptr; - bool initialized = false; - bool initialize_attempted = false; - const void* last_address = nullptr; - HMODULE module_handle = nullptr; - bool is_description_valid = false; - bool is_line_valid = false; - IMAGEHLP_LINE line = {sizeof(IMAGEHLP_LINE)}; - DWORD displacement = 0; - ptrdiff_t offset = 0; - SYMBOL_INFO info = init_symbol_info(); - char buffer[MAX_SYM_NAME]; - char module_path[MAX_PATH]; - const char* module_name = nullptr; - std::string_view function_name; - std::string function_address; + + IDebugClient* debug_client = nullptr; + IDebugSymbols* debug_symbols = nullptr; + IDebugControl* debug_control = nullptr; + bool attached = false; + bool initialize_attempted = false; + const void* last_address = nullptr; + bool is_description_valid = false; + bool is_line_valid = false; + char buffer[2000] = {}; + ULONG buffer_size = 0; + ULONG64 symbol_displacement = 0; + ULONG line = 0; + char file_name[MAX_PATH] = {}; + ULONG file_name_size = 0; + ULONG64 line_displacement = 0; }; stacktrace_global_data_t stacktrace_global_data; @@ -163,25 +145,50 @@ namespace { bool stacktrace_global_data_t::try_initialize() { if (!initialize_attempted) { - initialized = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), - &process_handle, PROCESS_QUERY_INFORMATION, false, 0) - && SymInitialize(process_handle, nullptr, true); - - atexit([] { - if (stacktrace_global_data.initialized) { - SymCleanup(stacktrace_global_data.process_handle); + // Deliberately not calling CoInitialize[Ex] + // DbgEng.h API works fine without it. COM initialization may have undesired interference with user's code + + if (SUCCEEDED(DebugCreate(IID_IDebugClient, reinterpret_cast(&debug_client))) + && SUCCEEDED(debug_client->QueryInterface(IID_IDebugSymbols, reinterpret_cast(&debug_symbols))) + && SUCCEEDED( + debug_client->QueryInterface(IID_IDebugControl, reinterpret_cast(&debug_control)))) { + attached = SUCCEEDED(debug_client->AttachProcess( + 0, GetCurrentProcessId(), DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); + if (attached) { + debug_control->WaitForEvent(0, INFINITE); } + } + } - if (stacktrace_global_data.process_handle) { - CloseHandle(stacktrace_global_data.process_handle); + atexit([] { + // "Phoenix singleton" - destroy and set to null, so that can initialize later again + + if (stacktrace_global_data.debug_client != nullptr) { + if (stacktrace_global_data.attached) { + stacktrace_global_data.debug_client->DetachProcesses(); + stacktrace_global_data.attached = false; } - stacktrace_global_data.initialize_attempted = false; - }); - initialize_attempted = true; - } + stacktrace_global_data.debug_client->Release(); + stacktrace_global_data.debug_client = nullptr; + } + + if (stacktrace_global_data.debug_control != nullptr) { + stacktrace_global_data.debug_control->Release(); + stacktrace_global_data.debug_control = nullptr; + } + + if (stacktrace_global_data.debug_symbols != nullptr) { + stacktrace_global_data.debug_symbols->Release(); + stacktrace_global_data.debug_symbols = nullptr; + } + + stacktrace_global_data.initialize_attempted = false; + }); + + initialize_attempted = true; - return initialized; + return stacktrace_global_data.debug_symbols != nullptr; } From 1e96c7a5178c742cf425f03a55e238b28334adf0 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 3 Feb 2022 17:45:31 +0200 Subject: [PATCH 032/131] clang format --- stl/src/stacktrace.cpp | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 1434e7db81..b27020c8df 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -39,7 +39,7 @@ namespace { class stacktrace_global_data_t { public: constexpr stacktrace_global_data_t() noexcept = default; - constexpr ~stacktrace_global_data_t() = default; + constexpr ~stacktrace_global_data_t() = default; stacktrace_global_data_t(const stacktrace_global_data_t&) = delete; stacktrace_global_data_t& operator=(const stacktrace_global_data_t) = delete; @@ -62,8 +62,7 @@ namespace { } if (symbol_displacement != 0) { - return std::format( - "{}+{:#x}", std::string_view(buffer, buffer_size), symbol_displacement); + return std::format("{}+{:#x}", std::string_view(buffer, buffer_size), symbol_displacement); } else { return std::string(std::string_view(buffer, buffer_size)); } @@ -111,8 +110,8 @@ namespace { if (!is_line_valid) { bool success = try_initialize() - && SUCCEEDED(debug_symbols->GetLineByOffset(reinterpret_cast(address), &line, file_name, - static_cast(std::size(file_name)), &file_name_size, &line_displacement)); + && SUCCEEDED(debug_symbols->GetLineByOffset(reinterpret_cast(address), &line, file_name, + static_cast(std::size(file_name)), &file_name_size, &line_displacement)); if (!success) { line = 0; file_name_size = 0; @@ -122,22 +121,22 @@ namespace { } } - - IDebugClient* debug_client = nullptr; - IDebugSymbols* debug_symbols = nullptr; - IDebugControl* debug_control = nullptr; - bool attached = false; - bool initialize_attempted = false; - const void* last_address = nullptr; - bool is_description_valid = false; - bool is_line_valid = false; - char buffer[2000] = {}; - ULONG buffer_size = 0; - ULONG64 symbol_displacement = 0; - ULONG line = 0; - char file_name[MAX_PATH] = {}; - ULONG file_name_size = 0; - ULONG64 line_displacement = 0; + + IDebugClient* debug_client = nullptr; + IDebugSymbols* debug_symbols = nullptr; + IDebugControl* debug_control = nullptr; + bool attached = false; + bool initialize_attempted = false; + const void* last_address = nullptr; + bool is_description_valid = false; + bool is_line_valid = false; + char buffer[2000] = {}; + ULONG buffer_size = 0; + ULONG64 symbol_displacement = 0; + ULONG line = 0; + char file_name[MAX_PATH] = {}; + ULONG file_name_size = 0; + ULONG64 line_displacement = 0; }; stacktrace_global_data_t stacktrace_global_data; From 22560884b3c307d162e1726665c4b750c9c3a8f8 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 3 Feb 2022 18:10:19 +0200 Subject: [PATCH 033/131] fix link --- stl/src/stacktrace.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index b27020c8df..f0783695ff 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -11,6 +11,8 @@ #include // clang-format on +#pragma comment(lib, "DbgEng.lib") + namespace { struct com_release_t { From 67f96d5d9008916dfe5ff755a2aafcc354ab006d Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 17:37:52 +0200 Subject: [PATCH 034/131] Functional nightmare --- stl/inc/stacktrace | 46 +++++-- stl/src/stacktrace.cpp | 297 +++++++++++++++++++++++------------------ 2 files changed, 204 insertions(+), 139 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index babaf44aee..cf60ef3f61 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -25,14 +25,34 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -[[nodiscard]] unsigned short __stdcall __std_stacktrace_capture( +using _Stacktrace_string_fill_callback = size_t (*)(char*, size_t, void* _Context); + +using _Stacktrace_string_fill = size_t (*)(size_t, void* _String, void* _Context, _Stacktrace_string_fill_callback); + +struct _Stacktrace_string_fill_op { + size_t operator()(char* _Data, size_t _Size) { + return _Callback(_Data, _Size, _Context); + } + + _Stacktrace_string_fill_callback _Callback; + void* _Context; +}; + +inline size_t _Stacktrace_string_fill_impl( + size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback) { + static_cast<_STD string*>(_String)->resize_and_overwrite(_Size, _Stacktrace_string_fill_op{_Callback, _Context}); + return static_cast<_STD string*>(_String)->size(); +} + +unsigned short __stdcall __std_stacktrace_capture( unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash); -[[nodiscard]] _STD string __stdcall __std_stacktrace_address_to_string(const void* _Address); -[[nodiscard]] _STD string __stdcall __std_stacktrace_description(const void* _Address); -[[nodiscard]] _STD string __stdcall __std_stacktrace_source_file(const void* _Address); +void __stdcall __std_stacktrace_address_to_string(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill); +void __stdcall __std_stacktrace_description(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill); +void __stdcall __std_stacktrace_source_file(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill); [[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address); -[[nodiscard]] _STD string __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size); +void __stdcall __std_stacktrace_to_string( + const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill); _STD_BEGIN class stacktrace_entry { @@ -54,11 +74,15 @@ public: } [[nodiscard]] string description() const { - return __std_stacktrace_description(_Address); + string _Result; + __std_stacktrace_description(_Address, &_Result, _Stacktrace_string_fill_impl); + return _Result; } [[nodiscard]] string source_file() const { - return __std_stacktrace_source_file(_Address); + string _Result; + __std_stacktrace_source_file(_Address, &_Result, _Stacktrace_string_fill_impl); + return _Result; } [[nodiscard]] uint_least32_t source_line() const { @@ -239,12 +263,16 @@ void swap(basic_stacktrace<_Al>& _Ax, basic_stacktrace<_Al>& _Bx) noexcept(noexc } [[nodiscard]] inline string to_string(const stacktrace_entry& _Fx) { - return __std_stacktrace_address_to_string(_Fx.native_handle()); + string _Result; + __std_stacktrace_address_to_string(_Fx.native_handle(), &_Result, _Stacktrace_string_fill_impl); + return _Result; } template [[nodiscard]] string to_string(const basic_stacktrace<_Al>& _St) { - return __std_stacktrace_to_string(_St._Data(), _St.size()); + string _Result; + __std_stacktrace_to_string(_St._Data(), _St.size(), &_Result, _Stacktrace_string_fill_impl); + return _Result; } template diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index f0783695ff..abe473b90e 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -4,7 +4,6 @@ #include #include #include -#include // clang-format off #include // should be before any header that includes @@ -13,8 +12,20 @@ #pragma comment(lib, "DbgEng.lib") +using _Stacktrace_string_fill_callback = size_t (*)(char*, size_t, void* _Context); + +using _Stacktrace_string_fill = size_t (*)(size_t, void* _Str, void* _Context, _Stacktrace_string_fill_callback); + namespace { + template + size_t string_fill(_Stacktrace_string_fill callback, size_t size, void* str, F f) { + return callback(size, str, &f, [] (char* s, size_t sz, void* context) -> size_t { + return (*static_cast(context))(s, sz); + }); + } + + struct com_release_t { void operator()(auto* p) { p->Release(); @@ -38,158 +49,174 @@ namespace { SRWLOCK* locked; }; - class stacktrace_global_data_t { - public: - constexpr stacktrace_global_data_t() noexcept = default; - constexpr ~stacktrace_global_data_t() = default; + IDebugClient* debug_client = nullptr; + IDebugSymbols* debug_symbols = nullptr; + IDebugControl* debug_control = nullptr; + bool attached = false; + bool initialize_attempted = false; - stacktrace_global_data_t(const stacktrace_global_data_t&) = delete; - stacktrace_global_data_t& operator=(const stacktrace_global_data_t) = delete; + SRWLOCK srw = SRWLOCK_INIT; - [[nodiscard]] std::string description(const void* const address) { - clear_if_wrong_address(address); + bool try_initialize() { + if (!initialize_attempted) { + // Deliberately not calling CoInitialize[Ex] + // DbgEng.h API works fine without it. COM initialization may have undesired interference with user's code - if (!is_description_valid) { - bool success = try_initialize() - && SUCCEEDED(debug_symbols->GetNameByOffset(reinterpret_cast(address), buffer, - static_cast(std::size(buffer)), &buffer_size, &symbol_displacement)); + if (SUCCEEDED(DebugCreate(IID_IDebugClient, reinterpret_cast(&debug_client))) + && SUCCEEDED(debug_client->QueryInterface(IID_IDebugSymbols, reinterpret_cast(&debug_symbols))) + && SUCCEEDED( + debug_client->QueryInterface(IID_IDebugControl, reinterpret_cast(&debug_control)))) { + attached = SUCCEEDED(debug_client->AttachProcess( + 0, GetCurrentProcessId(), DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); + if (attached) { + debug_control->WaitForEvent(0, INFINITE); + } + } + } - if (!success) { - buffer_size = - static_cast(std::format_to_n(buffer, std::size(buffer), "{}", address).out - buffer); - symbol_displacement = 0; + atexit([] { + // "Phoenix singleton" - destroy and set to null, so that can initialize later again + + if (debug_client != nullptr) { + if (attached) { + debug_client->DetachProcesses(); + attached = false; } - is_description_valid = true; + debug_client->Release(); + debug_client = nullptr; } - if (symbol_displacement != 0) { - return std::format("{}+{:#x}", std::string_view(buffer, buffer_size), symbol_displacement); - } else { - return std::string(std::string_view(buffer, buffer_size)); + if (debug_control != nullptr) { + debug_control->Release(); + debug_control = nullptr; } - } - [[nodiscard]] std::string source_file(const void* const address) { - initialize_line(address); + if (debug_symbols != nullptr) { + debug_symbols->Release(); + debug_symbols = nullptr; + } - return std::string(std::string_view(file_name, file_name_size)); - } + initialize_attempted = false; + }); - [[nodiscard]] unsigned source_line(const void* const address) { - initialize_line(address); + initialize_attempted = true; + + return debug_symbols != nullptr; + } - return line; + size_t get_description(const void* const address, void* str, size_t off, _Stacktrace_string_fill fill) { + if (!try_initialize()) { + return 0; } - [[nodiscard]] std::string address_to_string(const void* _Address) { + size_t size = 4; // a guess, will retry with greater if wrong + + HRESULT hr = E_UNEXPECTED; + + ULONG64 displacement = 0; - auto cur_line = source_line(_Address); - auto cur_desc = description(_Address); + for (;;) { + ULONG new_size = 0; - if (cur_line == 0) { - return cur_desc; + size_t new_off = string_fill( + fill, off + size, str, [address, off, size, &new_size, &hr, &displacement](char* s, size_t) { + + hr = debug_symbols->GetNameByOffset( + reinterpret_cast(address), s + off, static_cast(size), &new_size, &displacement); + + return (hr == S_OK) ? off + new_size - 1 : off; + }); + + if (hr == S_OK) { + off = new_off; + break; + } else if (hr == S_FALSE) { + size = new_size; // retry with bigger buffer } else { - return std::format("{}({}): {}", source_file(_Address), cur_line, cur_desc); + return off; } } + if (displacement != 0) { + constexpr size_t max_disp_num = std::size("+0x1111222233334444") - 1; // maximum possible line number - private: - bool try_initialize(); - - void clear_if_wrong_address(const void* const address) { - if (last_address != address) { - is_description_valid = false; - is_line_valid = false; - last_address = address; - } + off = string_fill(fill, off + max_disp_num, str, [displacement, off](char* s, size_t) { + return std::format_to_n(s + off, max_disp_num, "+{:#x}", displacement).out - s; + }); } - void initialize_line(const void* const address) { - clear_if_wrong_address(address); - - if (!is_line_valid) { - bool success = - try_initialize() - && SUCCEEDED(debug_symbols->GetLineByOffset(reinterpret_cast(address), &line, file_name, - static_cast(std::size(file_name)), &file_name_size, &line_displacement)); - if (!success) { - line = 0; - file_name_size = 0; - line_displacement = 0; - } - is_line_valid = true; - } + return off; + } + + + size_t source_file(const void* const address, void* str, size_t off, ULONG* line, _Stacktrace_string_fill fill) { + if (!try_initialize()) { + return 0; } + HRESULT hr = E_UNEXPECTED; + size_t size = 4; // a guess, will retry with greater if wrong - IDebugClient* debug_client = nullptr; - IDebugSymbols* debug_symbols = nullptr; - IDebugControl* debug_control = nullptr; - bool attached = false; - bool initialize_attempted = false; - const void* last_address = nullptr; - bool is_description_valid = false; - bool is_line_valid = false; - char buffer[2000] = {}; - ULONG buffer_size = 0; - ULONG64 symbol_displacement = 0; - ULONG line = 0; - char file_name[MAX_PATH] = {}; - ULONG file_name_size = 0; - ULONG64 line_displacement = 0; - }; + for (;;) { + ULONG new_size = 0; - stacktrace_global_data_t stacktrace_global_data; - SRWLOCK srw = SRWLOCK_INIT; + size_t new_off = + string_fill(fill, off + size, str, [address, off, size, line, &new_size, &hr](char* s, size_t) { - bool stacktrace_global_data_t::try_initialize() { - if (!initialize_attempted) { - // Deliberately not calling CoInitialize[Ex] - // DbgEng.h API works fine without it. COM initialization may have undesired interference with user's code + hr = debug_symbols->GetLineByOffset( + reinterpret_cast(address), line, s + off, static_cast(size), &new_size, nullptr); + + return (hr == S_OK) ? off + new_size - 1 : off; + }); - if (SUCCEEDED(DebugCreate(IID_IDebugClient, reinterpret_cast(&debug_client))) - && SUCCEEDED(debug_client->QueryInterface(IID_IDebugSymbols, reinterpret_cast(&debug_symbols))) - && SUCCEEDED( - debug_client->QueryInterface(IID_IDebugControl, reinterpret_cast(&debug_control)))) { - attached = SUCCEEDED(debug_client->AttachProcess( - 0, GetCurrentProcessId(), DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); - if (attached) { - debug_control->WaitForEvent(0, INFINITE); + if (hr == S_OK) { + off = new_off; + break; + } else if (hr == S_FALSE) { + size = new_size; // retry with bigger buffer + } else { + if (line != nullptr) { + *line = 0; } + + return off; } } - atexit([] { - // "Phoenix singleton" - destroy and set to null, so that can initialize later again - - if (stacktrace_global_data.debug_client != nullptr) { - if (stacktrace_global_data.attached) { - stacktrace_global_data.debug_client->DetachProcesses(); - stacktrace_global_data.attached = false; - } + return off; + } - stacktrace_global_data.debug_client->Release(); - stacktrace_global_data.debug_client = nullptr; - } + [[nodiscard]] unsigned source_line(const void* const address) { + if (!try_initialize()) { + return 0; + } + + ULONG line = 0; - if (stacktrace_global_data.debug_control != nullptr) { - stacktrace_global_data.debug_control->Release(); - stacktrace_global_data.debug_control = nullptr; - } + if (FAILED(debug_symbols->GetLineByOffset(reinterpret_cast(address), &line, nullptr, + 0, nullptr, nullptr))) { + return 0; + } + + return line; + } - if (stacktrace_global_data.debug_symbols != nullptr) { - stacktrace_global_data.debug_symbols->Release(); - stacktrace_global_data.debug_symbols = nullptr; - } + size_t address_to_string(const void* address, void* str, size_t off, _Stacktrace_string_fill fill) { + ULONG line = 0; + + off = source_file(address, str, off, &line, fill); - stacktrace_global_data.initialize_attempted = false; - }); + if (line != 0) { - initialize_attempted = true; + constexpr size_t max_line_num = std::size("(4294967295): ") - 1; // maximum possible line number + + off = string_fill(fill, off + max_line_num, str, [line, off](char* s, size_t) { + return std::format_to_n(s + off, max_line_num, "({}): ", line).out - s; + }); + } - return stacktrace_global_data.debug_symbols != nullptr; + return get_description(address, str, off, fill); } @@ -203,38 +230,48 @@ namespace { return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); } -[[nodiscard]] std::string __stdcall __std_stacktrace_description(const void* _Address) { +void __stdcall __std_stacktrace_description( + const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { srw_lock_guard lock{srw}; - return stacktrace_global_data.description(_Address); + + get_description(_Address, _Str, 0, _Fill); } -[[nodiscard]] std::string __stdcall __std_stacktrace_source_file(const void* _Address) { +void __stdcall __std_stacktrace_source_file( + const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { srw_lock_guard lock{srw}; - return stacktrace_global_data.source_file(_Address); + + source_file(_Address, _Str, 0, nullptr, _Fill); } -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) { +unsigned __stdcall __std_stacktrace_source_line(const void* _Address) { srw_lock_guard lock{srw}; - return stacktrace_global_data.source_line(_Address); + + return source_line(_Address); } -[[nodiscard]] std::string __stdcall __std_stacktrace_address_to_string(const void* _Address) { +void __stdcall __std_stacktrace_address_to_string( + const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { srw_lock_guard lock{srw}; - return stacktrace_global_data.address_to_string(_Address); + + address_to_string(_Address, _Str, 0, _Fill); } -[[nodiscard]] std::string __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size) { +void __stdcall __std_stacktrace_to_string( + const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill) { srw_lock_guard lock{srw}; + auto data = reinterpret_cast(_Addresses); - std::string result; + + size_t off = 0; + for (std::size_t i = 0; i != _Size; ++i) { - auto str = stacktrace_global_data.address_to_string(data[i]); - if (!result.empty()) { - result.push_back('\n'); - result.append(str); - } else { - result = std::move(str); + if (off != 0) { + off = string_fill(_Fill, off + 1, _Str, [](char* s, size_t sz) { + s[sz - 1] = '\n'; + return sz; + }); } + off = address_to_string(data[i], _Str, off, _Fill); } - return result; } From 7cc3d113463c49494de0c4b1ca94fbb2ee8fea61 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 17:51:21 +0200 Subject: [PATCH 035/131] clang format --- stl/src/stacktrace.cpp | 50 +++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index abe473b90e..923ee7b2b1 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -18,11 +18,10 @@ using _Stacktrace_string_fill = size_t (*)(size_t, void* _Str, void* _Context, _ namespace { - template + template size_t string_fill(_Stacktrace_string_fill callback, size_t size, void* str, F f) { - return callback(size, str, &f, [] (char* s, size_t sz, void* context) -> size_t { - return (*static_cast(context))(s, sz); - }); + return callback(size, str, &f, + [](char* s, size_t sz, void* context) -> size_t { return (*static_cast(context))(s, sz); }); } @@ -121,9 +120,8 @@ namespace { size_t new_off = string_fill( fill, off + size, str, [address, off, size, &new_size, &hr, &displacement](char* s, size_t) { - - hr = debug_symbols->GetNameByOffset( - reinterpret_cast(address), s + off, static_cast(size), &new_size, &displacement); + hr = debug_symbols->GetNameByOffset(reinterpret_cast(address), s + off, + static_cast(size), &new_size, &displacement); return (hr == S_OK) ? off + new_size - 1 : off; }); @@ -163,12 +161,11 @@ namespace { size_t new_off = string_fill(fill, off + size, str, [address, off, size, line, &new_size, &hr](char* s, size_t) { + hr = debug_symbols->GetLineByOffset(reinterpret_cast(address), line, s + off, + static_cast(size), &new_size, nullptr); - hr = debug_symbols->GetLineByOffset( - reinterpret_cast(address), line, s + off, static_cast(size), &new_size, nullptr); - - return (hr == S_OK) ? off + new_size - 1 : off; - }); + return (hr == S_OK) ? off + new_size - 1 : off; + }); if (hr == S_OK) { off = new_off; @@ -191,28 +188,28 @@ namespace { if (!try_initialize()) { return 0; } - + ULONG line = 0; - if (FAILED(debug_symbols->GetLineByOffset(reinterpret_cast(address), &line, nullptr, - 0, nullptr, nullptr))) { + if (FAILED(debug_symbols->GetLineByOffset( + reinterpret_cast(address), &line, nullptr, 0, nullptr, nullptr))) { return 0; } - + return line; } size_t address_to_string(const void* address, void* str, size_t off, _Stacktrace_string_fill fill) { ULONG line = 0; - + off = source_file(address, str, off, &line, fill); if (line != 0) { constexpr size_t max_line_num = std::size("(4294967295): ") - 1; // maximum possible line number - - off = string_fill(fill, off + max_line_num, str, [line, off](char* s, size_t) { - return std::format_to_n(s + off, max_line_num, "({}): ", line).out - s; + + off = string_fill(fill, off + max_line_num, str, [line, off](char* s, size_t) { + return std::format_to_n(s + off, max_line_num, "({}): ", line).out - s; }); } @@ -230,17 +227,15 @@ namespace { return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); } -void __stdcall __std_stacktrace_description( - const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { +void __stdcall __std_stacktrace_description(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { srw_lock_guard lock{srw}; get_description(_Address, _Str, 0, _Fill); } -void __stdcall __std_stacktrace_source_file( - const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { +void __stdcall __std_stacktrace_source_file(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { srw_lock_guard lock{srw}; - + source_file(_Address, _Str, 0, nullptr, _Fill); } @@ -250,8 +245,7 @@ unsigned __stdcall __std_stacktrace_source_line(const void* _Address) { return source_line(_Address); } -void __stdcall __std_stacktrace_address_to_string( - const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { +void __stdcall __std_stacktrace_address_to_string(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { srw_lock_guard lock{srw}; address_to_string(_Address, _Str, 0, _Fill); @@ -264,7 +258,7 @@ void __stdcall __std_stacktrace_to_string( auto data = reinterpret_cast(_Addresses); size_t off = 0; - + for (std::size_t i = 0; i != _Size; ++i) { if (off != 0) { off = string_fill(_Fill, off + 1, _Str, [](char* s, size_t sz) { From f098d7f759b5e12b09b997d87ab65a073b937f6f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 18:22:30 +0200 Subject: [PATCH 036/131] desatellite --- stl/CMakeLists.txt | 28 ++++++------------- .../stl_base/stl.files.settings.targets | 1 + stl/src/stacktrace.cpp | 5 ++++ 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 4072f6c868..ec2c2a3769 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -257,6 +257,7 @@ set(IMPLIB_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/locale0_implib.cpp ${CMAKE_CURRENT_LIST_DIR}/src/nothrow.cpp ${CMAKE_CURRENT_LIST_DIR}/src/sharedmutex.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/stacktrace.cpp ${CMAKE_CURRENT_LIST_DIR}/src/syserror_import_lib.cpp ${CMAKE_CURRENT_LIST_DIR}/src/vector_algorithms.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xonce2.cpp @@ -431,7 +432,6 @@ set(STATIC_SOURCES ${SOURCES_SATELLITE_2} ${SOURCES_SATELLITE_ATOMIC_WAIT} ${SOURCES_SATELLITE_CODECVT_IDS} - ${SOURCES_SATELLITE_STACKTRACE} ) # Objs that exist in all satellite DLLs @@ -462,7 +462,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_eha_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHa") add_library(msvcp${D_SUFFIX} SHARED) - target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects msvcp${D_SUFFIX}_init_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects msvcp${D_SUFFIX}_init_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_base${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -483,7 +483,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp_1${D_SUFFIX}_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp_1${D_SUFFIX} SHARED) - target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -496,7 +496,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_link_libraries(msvcp_2${D_SUFFIX}_objects PRIVATE Boost::math) add_library(msvcp_2${D_SUFFIX} SHARED) - target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -518,31 +518,19 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO file(WRITE "${_ATOMIC_WAIT_DEF_NAME}" "${_ATOMIC_WAIT_DEF_CONTENTS}") add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${_ATOMIC_WAIT_DEF_NAME}") - target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib") + target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "DbgEng.lib") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "${_ATOMIC_WAIT_OUTPUT_NAME}") target_link_options(msvcp${D_SUFFIX}_atomic_wait PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") - # msvcp140_stacktrace.dll (the stacktrace satellite) - add_library(msvcp${D_SUFFIX}_stacktrace_objects OBJECT ${SOURCES_SATELLITE_STACKTRACE}) - target_compile_definitions(msvcp${D_SUFFIX}_stacktrace_objects PRIVATE "_BUILDING_SATELLITE_STACKTRACE;_DLL;${THIS_CONFIG_DEFINITIONS}") - target_compile_options(msvcp${D_SUFFIX}_stacktrace_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") - - add_library(msvcp${D_SUFFIX}_stacktrace SHARED "${CMAKE_CURRENT_LIST_DIR}/src/msvcp_stacktrace.def") - target_link_libraries(msvcp${D_SUFFIX}_stacktrace PRIVATE msvcp${D_SUFFIX}_stacktrace_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") - set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_stacktrace${D_SUFFIX}${VCLIBS_SUFFIX}") - set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - set_target_properties(msvcp${D_SUFFIX}_stacktrace PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_stacktrace${VCLIBS_SUFFIX}") - target_link_options(msvcp${D_SUFFIX}_stacktrace PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") - # msvcp140_codecvt_ids.dll add_library(msvcp${D_SUFFIX}_codecvt_ids_objects OBJECT ${SOURCES_SATELLITE_CODECVT_IDS}) target_compile_definitions(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE "_BUILDING_SATELLITE_CODECVT_IDS;_DLL;${THIS_CONFIG_DEFINITIONS}") target_compile_options(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp${D_SUFFIX}_codecvt_ids SHARED) - target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_codecvt_ids${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_codecvt_ids${VCLIBS_SUFFIX}") @@ -551,8 +539,8 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO # import library add_library(msvcp${D_SUFFIX}_implib STATIC ${HEADERS}) target_link_libraries(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX}_implib_objects) - add_dependencies(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX} msvcp_1${D_SUFFIX} msvcp_2${D_SUFFIX} msvcp${D_SUFFIX}_atomic_wait msvcp${D_SUFFIX}_codecvt_ids msvcp${D_SUFFIX}_stacktrace) - set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$;$;$") + add_dependencies(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX} msvcp_1${D_SUFFIX} msvcp_2${D_SUFFIX} msvcp${D_SUFFIX}_atomic_wait msvcp${D_SUFFIX}_codecvt_ids) + set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$;$") set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES ARCHIVE_OUTPUT_NAME "msvcprt${D_SUFFIX}") endfunction() diff --git a/stl/msbuild/stl_base/stl.files.settings.targets b/stl/msbuild/stl_base/stl.files.settings.targets index 3fb83607ac..3b7d6c1b22 100644 --- a/stl/msbuild/stl_base/stl.files.settings.targets +++ b/stl/msbuild/stl_base/stl.files.settings.targets @@ -166,6 +166,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception $(CrtRoot)\github\stl\src\locale0_implib.cpp; $(CrtRoot)\github\stl\src\nothrow.cpp; $(CrtRoot)\github\stl\src\sharedmutex.cpp; + $(CrtRoot)\github\stl\src\stacktrace.cpp; $(CrtRoot)\github\stl\src\syserror_import_lib.cpp; $(CrtRoot)\github\stl\src\vector_algorithms.cpp; $(CrtRoot)\github\stl\src\xonce2.cpp; diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 923ee7b2b1..f3680498cb 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -1,6 +1,11 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// This must be as small as possible, because its contents are +// injected into the msvcprt.lib and msvcprtd.lib import libraries. +// Do not include or define anything else here. +// In particular, basic_string must not be included here. + #include #include #include From dfb0700ee2a0e44afa003d3ca835d4cc30cc76b6 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 19:07:55 +0200 Subject: [PATCH 037/131] extern C --- stl/inc/stacktrace | 2 ++ stl/src/stacktrace.cpp | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index cf60ef3f61..3da0880dca 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -44,6 +44,7 @@ inline size_t _Stacktrace_string_fill_impl( return static_cast<_STD string*>(_String)->size(); } +_EXTERN_C unsigned short __stdcall __std_stacktrace_capture( unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash); @@ -53,6 +54,7 @@ void __stdcall __std_stacktrace_source_file(const void* _Address, void* _Str, _S [[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address); void __stdcall __std_stacktrace_to_string( const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill); +_END_EXTERN_C _STD_BEGIN class stacktrace_entry { diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index f3680498cb..5b9e43e082 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -17,25 +17,26 @@ #pragma comment(lib, "DbgEng.lib") +// The below function pointer types be in sync with + using _Stacktrace_string_fill_callback = size_t (*)(char*, size_t, void* _Context); using _Stacktrace_string_fill = size_t (*)(size_t, void* _Str, void* _Context, _Stacktrace_string_fill_callback); namespace { - template size_t string_fill(_Stacktrace_string_fill callback, size_t size, void* str, F f) { return callback(size, str, &f, [](char* s, size_t sz, void* context) -> size_t { return (*static_cast(context))(s, sz); }); } - struct com_release_t { void operator()(auto* p) { p->Release(); } }; + // TRANSITION, GH-2285. Use SRWLOCK instead of std::mutex to avoid nontrivial constructor and nontrivial destructor class _NODISCARD srw_lock_guard { public: explicit srw_lock_guard(SRWLOCK& locked_) noexcept : locked(&locked_) { @@ -58,8 +59,7 @@ namespace { IDebugControl* debug_control = nullptr; bool attached = false; bool initialize_attempted = false; - - SRWLOCK srw = SRWLOCK_INIT; + SRWLOCK srw = SRWLOCK_INIT; bool try_initialize() { if (!initialize_attempted) { @@ -114,10 +114,8 @@ namespace { return 0; } - size_t size = 4; // a guess, will retry with greater if wrong - - HRESULT hr = E_UNEXPECTED; - + size_t size = 20; // a guess, will retry with greater if wrong + HRESULT hr = E_UNEXPECTED; ULONG64 displacement = 0; for (;;) { @@ -152,14 +150,13 @@ namespace { return off; } - size_t source_file(const void* const address, void* str, size_t off, ULONG* line, _Stacktrace_string_fill fill) { if (!try_initialize()) { return 0; } - HRESULT hr = E_UNEXPECTED; - size_t size = 4; // a guess, will retry with greater if wrong + HRESULT hr = E_UNEXPECTED; + size_t size = 20; // a guess, will retry with greater if wrong for (;;) { ULONG new_size = 0; @@ -178,7 +175,7 @@ namespace { } else if (hr == S_FALSE) { size = new_size; // retry with bigger buffer } else { - if (line != nullptr) { + if (line) { *line = 0; } @@ -210,7 +207,6 @@ namespace { off = source_file(address, str, off, &line, fill); if (line != 0) { - constexpr size_t max_line_num = std::size("(4294967295): ") - 1; // maximum possible line number off = string_fill(fill, off + max_line_num, str, [line, off](char* s, size_t) { @@ -224,6 +220,7 @@ namespace { } // namespace +_EXTERN_C [[nodiscard]] unsigned short __stdcall __std_stacktrace_capture( unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash) { #ifdef _DEBUG @@ -274,3 +271,4 @@ void __stdcall __std_stacktrace_to_string( off = address_to_string(data[i], _Str, off, _Fill); } } +_END_EXTERN_C From 03c4751923a12f27f986af8af839bbe62873ac8c Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 19:08:38 +0200 Subject: [PATCH 038/131] desatellite++ --- stl/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index ec2c2a3769..7e677a0d6d 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -422,10 +422,6 @@ set(SOURCES_SATELLITE_CODECVT_IDS ${CMAKE_CURRENT_LIST_DIR}/src/ulocale.cpp ) -set(SOURCES_SATELLITE_STACKTRACE - ${CMAKE_CURRENT_LIST_DIR}/src/stacktrace.cpp -) - # Objs that exist only in libcpmt[d][01].lib. set(STATIC_SOURCES ${SOURCES_SATELLITE_1} From b71b67e5808ca8105f769b92f7fa255a2014da9e Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 19:14:49 +0200 Subject: [PATCH 039/131] unused --- stl/src/stacktrace.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 5b9e43e082..9f6728c391 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -30,12 +30,6 @@ namespace { [](char* s, size_t sz, void* context) -> size_t { return (*static_cast(context))(s, sz); }); } - struct com_release_t { - void operator()(auto* p) { - p->Release(); - } - }; - // TRANSITION, GH-2285. Use SRWLOCK instead of std::mutex to avoid nontrivial constructor and nontrivial destructor class _NODISCARD srw_lock_guard { public: From ce6d007c474cd6c0afb305c97efbc02bc1ac6606 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 19:39:46 +0200 Subject: [PATCH 040/131] atexit sync --- stl/src/stacktrace.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 9f6728c391..b8771330b3 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -73,6 +73,8 @@ namespace { } atexit([] { + srw_lock_guard lock{srw}; + // "Phoenix singleton" - destroy and set to null, so that can initialize later again if (debug_client != nullptr) { @@ -134,7 +136,7 @@ namespace { } if (displacement != 0) { - constexpr size_t max_disp_num = std::size("+0x1111222233334444") - 1; // maximum possible line number + constexpr size_t max_disp_num = std::size("+0x1111222233334444") - 1; // maximum possible offset off = string_fill(fill, off + max_disp_num, str, [displacement, off](char* s, size_t) { return std::format_to_n(s + off, max_disp_num, "+{:#x}", displacement).out - s; From 82a6c7caa0d714e0300cee51ee1cc404ad35f0be Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 20:02:29 +0200 Subject: [PATCH 041/131] top level `const` --- stl/inc/stacktrace | 2 +- stl/src/stacktrace.cpp | 41 +++++++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 3da0880dca..35abfbd8a6 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -39,7 +39,7 @@ struct _Stacktrace_string_fill_op { }; inline size_t _Stacktrace_string_fill_impl( - size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback) { + const size_t _Size, void* const _String, void* const _Context, const _Stacktrace_string_fill_callback _Callback) { static_cast<_STD string*>(_String)->resize_and_overwrite(_Size, _Stacktrace_string_fill_op{_Callback, _Context}); return static_cast<_STD string*>(_String)->size(); } diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index b8771330b3..500867b5b6 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -25,7 +25,7 @@ using _Stacktrace_string_fill = size_t (*)(size_t, void* _Str, void* _Context, _ namespace { template - size_t string_fill(_Stacktrace_string_fill callback, size_t size, void* str, F f) { + size_t string_fill(const _Stacktrace_string_fill callback, const size_t size, void* const str, F f) { return callback(size, str, &f, [](char* s, size_t sz, void* context) -> size_t { return (*static_cast(context))(s, sz); }); } @@ -45,7 +45,7 @@ namespace { srw_lock_guard& operator=(const srw_lock_guard&) = delete; private: - SRWLOCK* locked; + SRWLOCK* const locked; }; IDebugClient* debug_client = nullptr; @@ -105,7 +105,7 @@ namespace { return debug_symbols != nullptr; } - size_t get_description(const void* const address, void* str, size_t off, _Stacktrace_string_fill fill) { + size_t get_description(const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { if (!try_initialize()) { return 0; } @@ -146,7 +146,8 @@ namespace { return off; } - size_t source_file(const void* const address, void* str, size_t off, ULONG* line, _Stacktrace_string_fill fill) { + size_t source_file( + const void* const address, void* const str, size_t off, ULONG* const line, const _Stacktrace_string_fill fill) { if (!try_initialize()) { return 0; } @@ -197,7 +198,8 @@ namespace { return line; } - size_t address_to_string(const void* address, void* str, size_t off, _Stacktrace_string_fill fill) { + size_t address_to_string( + const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { ULONG line = 0; off = source_file(address, str, off, &line, fill); @@ -217,43 +219,46 @@ namespace { } // namespace _EXTERN_C -[[nodiscard]] unsigned short __stdcall __std_stacktrace_capture( - unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash) { +[[nodiscard]] unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, + const unsigned long _FramesToCapture, void** const _BackTrace, unsigned long* const _BackTraceHash) { #ifdef _DEBUG _FramesToSkip += 1; // compensate absense of tail call optimization here #endif return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); } -void __stdcall __std_stacktrace_description(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { - srw_lock_guard lock{srw}; +void __stdcall __std_stacktrace_description( + const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) { + const srw_lock_guard lock{srw}; get_description(_Address, _Str, 0, _Fill); } -void __stdcall __std_stacktrace_source_file(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { - srw_lock_guard lock{srw}; +void __stdcall __std_stacktrace_source_file( + const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) { + const srw_lock_guard lock{srw}; source_file(_Address, _Str, 0, nullptr, _Fill); } -unsigned __stdcall __std_stacktrace_source_line(const void* _Address) { - srw_lock_guard lock{srw}; +unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) { + const srw_lock_guard lock{srw}; return source_line(_Address); } -void __stdcall __std_stacktrace_address_to_string(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) { - srw_lock_guard lock{srw}; +void __stdcall __std_stacktrace_address_to_string( + const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) { + const srw_lock_guard lock{srw}; address_to_string(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_to_string( - const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill) { - srw_lock_guard lock{srw}; + const void* const _Addresses, const size_t _Size, void* const _Str, const _Stacktrace_string_fill _Fill) { + const srw_lock_guard lock{srw}; - auto data = reinterpret_cast(_Addresses); + const auto data = reinterpret_cast(_Addresses); size_t off = 0; From 7aee4617bfc128231dc7e71a09720dfe81863c4c Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 5 Feb 2022 20:03:43 +0200 Subject: [PATCH 042/131] #exclude --- stl/src/stacktrace.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 500867b5b6..52a45d5298 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -7,8 +7,6 @@ // In particular, basic_string must not be included here. #include -#include -#include // clang-format off #include // should be before any header that includes From 8dc8468c9108dc9fe1cbdf51647637b251b12bd8 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 10:12:49 +0200 Subject: [PATCH 043/131] unextern C for exception safety --- stl/inc/stacktrace | 13 ++++++++----- stl/src/stacktrace.cpp | 5 ++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 35abfbd8a6..1342aaa9e3 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -30,7 +30,7 @@ using _Stacktrace_string_fill_callback = size_t (*)(char*, size_t, void* _Contex using _Stacktrace_string_fill = size_t (*)(size_t, void* _String, void* _Context, _Stacktrace_string_fill_callback); struct _Stacktrace_string_fill_op { - size_t operator()(char* _Data, size_t _Size) { + size_t operator()(char* _Data, size_t _Size) noexcept { return _Callback(_Data, _Size, _Context); } @@ -45,8 +45,12 @@ inline size_t _Stacktrace_string_fill_impl( } _EXTERN_C -unsigned short __stdcall __std_stacktrace_capture( - unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash); +unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, unsigned long _FramesToCapture, + void** _BackTrace, unsigned long* _BackTraceHash) noexcept; +_END_EXTERN_C + +// Below exports are not extern "C" - these functions may throw +// (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) void __stdcall __std_stacktrace_address_to_string(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill); void __stdcall __std_stacktrace_description(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill); @@ -54,7 +58,7 @@ void __stdcall __std_stacktrace_source_file(const void* _Address, void* _Str, _S [[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address); void __stdcall __std_stacktrace_to_string( const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill); -_END_EXTERN_C + _STD_BEGIN class stacktrace_entry { @@ -242,7 +246,6 @@ public: return _Frames.data(); } - private: static constexpr size_t _Max_frames = 0xFFFF; diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 52a45d5298..d556f19975 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -224,6 +224,10 @@ _EXTERN_C #endif return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); } +_END_EXTERN_C + +// Below exports are not extern "C" - these functions may throw +// (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) void __stdcall __std_stacktrace_description( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) { @@ -270,4 +274,3 @@ void __stdcall __std_stacktrace_to_string( off = address_to_string(data[i], _Str, off, _Fill); } } -_END_EXTERN_C From 1cfb5c77eda6ca664fe20211791f4689b07c6f58 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 10:25:22 +0200 Subject: [PATCH 044/131] still extern "C" --- stl/inc/stacktrace | 25 ++++++++++++++----------- stl/src/stacktrace.cpp | 19 +++++++++---------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 1342aaa9e3..10c7ec968f 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -47,18 +47,21 @@ inline size_t _Stacktrace_string_fill_impl( _EXTERN_C unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash) noexcept; -_END_EXTERN_C - -// Below exports are not extern "C" - these functions may throw -// (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) - -void __stdcall __std_stacktrace_address_to_string(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill); -void __stdcall __std_stacktrace_description(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill); -void __stdcall __std_stacktrace_source_file(const void* _Address, void* _Str, _Stacktrace_string_fill _Fill); -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address); -void __stdcall __std_stacktrace_to_string( - const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill); +// Some of these exports may throw (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) + +// clang-format off +void __stdcall __std_stacktrace_address_to_string( + const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); +void __stdcall __std_stacktrace_description( + const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); +void __stdcall __std_stacktrace_source_file( + const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) +void __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size, void* _Str, + _Stacktrace_string_fill) noexcept(false); +// clang-format on +_END_EXTERN_C _STD_BEGIN class stacktrace_entry { diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index d556f19975..0ee024b355 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -218,46 +218,44 @@ namespace { _EXTERN_C [[nodiscard]] unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, - const unsigned long _FramesToCapture, void** const _BackTrace, unsigned long* const _BackTraceHash) { + const unsigned long _FramesToCapture, void** const _BackTrace, unsigned long* const _BackTraceHash) noexcept { #ifdef _DEBUG _FramesToSkip += 1; // compensate absense of tail call optimization here #endif return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); } -_END_EXTERN_C -// Below exports are not extern "C" - these functions may throw -// (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) +// Some of these exports may throw (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) void __stdcall __std_stacktrace_description( - const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) { + const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; get_description(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_source_file( - const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) { + const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; source_file(_Address, _Str, 0, nullptr, _Fill); } -unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) { +unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { const srw_lock_guard lock{srw}; return source_line(_Address); } void __stdcall __std_stacktrace_address_to_string( - const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) { + const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; address_to_string(_Address, _Str, 0, _Fill); } -void __stdcall __std_stacktrace_to_string( - const void* const _Addresses, const size_t _Size, void* const _Str, const _Stacktrace_string_fill _Fill) { +void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const size_t _Size, void* const _Str, + const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; const auto data = reinterpret_cast(_Addresses); @@ -274,3 +272,4 @@ void __stdcall __std_stacktrace_to_string( off = address_to_string(data[i], _Str, off, _Fill); } } +_END_EXTERN_C From 5cdb7bd9b25c99152486d44d127e259c4303143e Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 10:50:12 +0200 Subject: [PATCH 045/131] build --- stl/inc/stacktrace | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 10c7ec968f..749eeadde8 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -30,7 +30,7 @@ using _Stacktrace_string_fill_callback = size_t (*)(char*, size_t, void* _Contex using _Stacktrace_string_fill = size_t (*)(size_t, void* _String, void* _Context, _Stacktrace_string_fill_callback); struct _Stacktrace_string_fill_op { - size_t operator()(char* _Data, size_t _Size) noexcept { + size_t operator()(char* _Data, size_t _Size) { return _Callback(_Data, _Size, _Context); } @@ -57,7 +57,7 @@ void __stdcall __std_stacktrace_description( const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); void __stdcall __std_stacktrace_source_file( const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address); void __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill) noexcept(false); // clang-format on From d760966297e55599ab995016cf43c5df5e4f7938 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 11:32:13 +0200 Subject: [PATCH 046/131] Compensate '\0' --- stl/src/stacktrace.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 0ee024b355..7bd455a571 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -118,7 +118,7 @@ namespace { size_t new_off = string_fill( fill, off + size, str, [address, off, size, &new_size, &hr, &displacement](char* s, size_t) { hr = debug_symbols->GetNameByOffset(reinterpret_cast(address), s + off, - static_cast(size), &new_size, &displacement); + static_cast(size + 1), &new_size, &displacement); return (hr == S_OK) ? off + new_size - 1 : off; }); @@ -159,7 +159,7 @@ namespace { size_t new_off = string_fill(fill, off + size, str, [address, off, size, line, &new_size, &hr](char* s, size_t) { hr = debug_symbols->GetLineByOffset(reinterpret_cast(address), line, s + off, - static_cast(size), &new_size, nullptr); + static_cast(size + 1), &new_size, nullptr); return (hr == S_OK) ? off + new_size - 1 : off; }); @@ -168,7 +168,7 @@ namespace { off = new_off; break; } else if (hr == S_FALSE) { - size = new_size; // retry with bigger buffer + size = new_size - 1; // retry with bigger buffer } else { if (line) { *line = 0; From a9d72ec32a3e10d8ee780c7e5f1e6986b5585efe Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 13:18:39 +0200 Subject: [PATCH 047/131] reuse capacity --- stl/inc/stacktrace | 27 ++++++++++++++++----------- stl/src/stacktrace.cpp | 8 +++++--- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 749eeadde8..38bd18464e 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -29,19 +29,24 @@ using _Stacktrace_string_fill_callback = size_t (*)(char*, size_t, void* _Contex using _Stacktrace_string_fill = size_t (*)(size_t, void* _String, void* _Context, _Stacktrace_string_fill_callback); -struct _Stacktrace_string_fill_op { - size_t operator()(char* _Data, size_t _Size) { - return _Callback(_Data, _Size, _Context); - } - - _Stacktrace_string_fill_callback _Callback; - void* _Context; -}; - inline size_t _Stacktrace_string_fill_impl( const size_t _Size, void* const _String, void* const _Context, const _Stacktrace_string_fill_callback _Callback) { - static_cast<_STD string*>(_String)->resize_and_overwrite(_Size, _Stacktrace_string_fill_op{_Callback, _Context}); - return static_cast<_STD string*>(_String)->size(); + if (_Callback) { + struct _Stacktrace_string_fill_op { + size_t operator()(char* _Data, size_t _Size) { + return _Callback(_Data, _Size, _Context); + } + + _Stacktrace_string_fill_callback _Callback; + void* _Context; + }; + + static_cast<_STD string*>(_String)->resize_and_overwrite( + _Size, _Stacktrace_string_fill_op{_Callback, _Context}); + return static_cast<_STD string*>(_String)->size(); + } else { + return static_cast<_STD string*>(_String)->capacity(); + } } _EXTERN_C diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 7bd455a571..eba164e545 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -108,7 +108,8 @@ namespace { return 0; } - size_t size = 20; // a guess, will retry with greater if wrong + // Initially pass the current capacity, will retry with bigger buffer if fails. + size_t size = fill(0, str, nullptr, nullptr) - off; HRESULT hr = E_UNEXPECTED; ULONG64 displacement = 0; @@ -127,7 +128,7 @@ namespace { off = new_off; break; } else if (hr == S_FALSE) { - size = new_size; // retry with bigger buffer + size = new_size - 1; // retry with bigger buffer } else { return off; } @@ -150,8 +151,9 @@ namespace { return 0; } + // Initially pass the current capacity, will retry with bigger buffer if fails. + size_t size = fill(0, str, nullptr, nullptr) - off; HRESULT hr = E_UNEXPECTED; - size_t size = 20; // a guess, will retry with greater if wrong for (;;) { ULONG new_size = 0; From 2186b325b896bd6c4ea2cbd0ddabd5bd1ea1c38c Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 13:21:51 +0200 Subject: [PATCH 048/131] noexcept --- stl/inc/stacktrace | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 38bd18464e..de060eedac 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -58,11 +58,15 @@ unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, u // clang-format off void __stdcall __std_stacktrace_address_to_string( const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); + void __stdcall __std_stacktrace_description( const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); + void __stdcall __std_stacktrace_source_file( const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address); + +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) noexcept; + void __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill) noexcept(false); // clang-format on From b1f637c628e6b3558f4de134aa6a33d0f1664e73 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 14:08:44 +0200 Subject: [PATCH 049/131] consistently exclude the current --- stl/inc/stacktrace | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index de060eedac..2d42977dcc 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -133,25 +133,29 @@ public: using size_type = size_t; using allocator_type = _Al; - [[nodiscard]] static basic_stacktrace current(const allocator_type& _Alloc = allocator_type()) noexcept { + // __declspec(noinline) to make the same behavior for debug and release. + // We force the current function to be always noinline and add its frame to skipped. + + [[nodiscard]] __declspec(noinline) static basic_stacktrace + current(const allocator_type& _Alloc = allocator_type()) noexcept { basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Alloc); - _Result._Frames.resize(__std_stacktrace_capture(0, static_cast(_Max_frames), + _Result._Frames.resize(__std_stacktrace_capture(1, static_cast(_Max_frames), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; } - [[nodiscard]] static basic_stacktrace current( - size_type _Skip, const allocator_type& _Alloc = allocator_type()) noexcept { + [[nodiscard]] __declspec(noinline) static basic_stacktrace + current(size_type _Skip, const allocator_type& _Alloc = allocator_type()) noexcept { basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Alloc); - _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip), + _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), static_cast(_Max_frames), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; } - [[nodiscard]] static basic_stacktrace current( - size_type _Skip, size_type _Max_depth, const allocator_type& _Alloc = allocator_type()) noexcept { + [[nodiscard]] __declspec(noinline) static basic_stacktrace + current(size_type _Skip, size_type _Max_depth, const allocator_type& _Alloc = allocator_type()) noexcept { basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Alloc); - _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip), + _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), static_cast(_Max_depth), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; } From 49be56a621eba4dd92fd4ffcf9166ce4b119fcd6 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 15:38:11 +0200 Subject: [PATCH 050/131] BE workaround --- stl/inc/stacktrace | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 2d42977dcc..d2b8f93d75 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -245,7 +245,17 @@ public: return _Result; } +#ifdef __cpp_lib_concepts return _Lhs._Frames <=> _Rhs._Frames; +#else // ^^^ __cpp_lib_concepts ^^^ / vvv !__cpp_lib_concepts vvv + for (size_t _Ix = 0, _Mx = _Lhs._Frames.size(); _Ix != _Mx; ++_Ix) { + if (_Lhs._Frames[_Ix] != _Rhs._Frames[_Ix]) { + return _Lhs._Frames[_Ix] <=> _Lhs._Frames[_Ix]; + } + } + + return strong_ordering::equal; +#endif // ^^^ !__cpp_lib_concepts ^^^ } void swap(basic_stacktrace& _Other) noexcept( From ab89b14a9f2baf87890134d11b71372bcbb3f19a Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 15:49:46 +0200 Subject: [PATCH 051/131] test --- tests/std/test.lst | 1 + tests/std/tests/P0881R7_stacktrace/env.lst | 6 + tests/std/tests/P0881R7_stacktrace/test.cpp | 199 ++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 tests/std/tests/P0881R7_stacktrace/env.lst create mode 100644 tests/std/tests/P0881R7_stacktrace/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index 9296abdddd..0f16eb590b 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -303,6 +303,7 @@ tests\P0784R7_library_machinery tests\P0784R7_library_support_for_more_constexpr_containers tests\P0798R8_monadic_operations_for_std_optional tests\P0811R3_midpoint_lerp +tests\P0881R7_stacktrace tests\P0896R4_common_iterator tests\P0896R4_common_iterator_death tests\P0896R4_counted_iterator diff --git a/tests/std/tests/P0881R7_stacktrace/env.lst b/tests/std/tests/P0881R7_stacktrace/env.lst new file mode 100644 index 0000000000..6abf6509cc --- /dev/null +++ b/tests/std/tests/P0881R7_stacktrace/env.lst @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst +RUNALL_CROSSLIST +PM_CL="/Zi" diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp new file mode 100644 index 0000000000..a1e7fbc9a6 --- /dev/null +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -0,0 +1,199 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; + +// Note: the bellow assumes tail call optimization disabled, which is in case in /Od + +stacktrace all_innermost() { + return stacktrace::current(); +} + +stacktrace all_inner() { + return all_innermost(); +} + +stacktrace all_outer() { + return all_inner(); +} + +stacktrace all_outermost() { + return all_outer(); +} + +stacktrace all_but_top_innermost() { + return stacktrace::current(1); +} + +stacktrace all_but_top_inner() { + return all_but_top_innermost(); +} + +stacktrace all_but_top_outer() { + return all_but_top_inner(); +} + +stacktrace all_but_top_outermost() { + return all_but_top_outer(); +} + +stacktrace three_excluding_top_innermost() { + return stacktrace::current(1, 3); +} + +stacktrace three_excluding_top_inner() { + return three_excluding_top_innermost(); +} + +stacktrace three_excluding_top_outer() { + return three_excluding_top_inner(); +} + +stacktrace three_excluding_top_outermost() { + return three_excluding_top_outer(); +} + +string trim_past_plus(string str) { + if (size_t pos = str.rfind("+", string::npos); pos != string::npos) { + str.resize(pos); + } + return str; +} + +string to_string_using_low_level_members(const stacktrace& st) { + stringstream ss; + for (const auto& i : st) { + auto l = i.source_line(); + if (l != 0) { + ss << i.source_file() << "(" << l << "): "; + } + ss << i.description() << "\n"; + } + return ss.str(); +} + +string to_string_using_stream_entry(const stacktrace& st) { + stringstream ss; + for (const auto& i : st) { + ss << i << "\n"; + } + return ss.str(); +} + +string to_string_using_to_string_entry(const stacktrace& st) { + stringstream ss; + for (const auto& i : st) { + ss << to_string(i) << "\n"; + } + return ss.str(); +} + +string to_string_using_stream(const stacktrace& st) { + stringstream ss; + ss << st << "\n"; + return ss.str(); +} + +string to_string_using_to_string(const stacktrace& st) { + return to_string(st) + "\n"; +} + + +int main() { + auto all = all_outermost(); + assert(all.size() >= 4); + assert(filesystem::path(all.at(0).source_file()).filename() == "test.cpp"sv); + assert(filesystem::path(all.at(1).source_file()).filename() == "test.cpp"sv); + assert(filesystem::path(all.at(2).source_file()).filename() == "test.cpp"sv); + assert(filesystem::path(all.at(3).source_file()).filename() == "test.cpp"sv); + + assert(all.at(0).source_line() == 15); + assert(all.at(1).source_line() == 19); + assert(all.at(2).source_line() == 23); + assert(all.at(3).source_line() == 27); + + assert(trim_past_plus(all.at(0).description()) == "P0881R7_stacktrace!all_innermost"sv); + assert(trim_past_plus(all.at(1).description()) == "P0881R7_stacktrace!all_inner"sv); + assert(trim_past_plus(all.at(2).description()) == "P0881R7_stacktrace!all_outer"sv); + assert(trim_past_plus(all.at(3).description()) == "P0881R7_stacktrace!all_outermost"sv); + + auto all_but_top = all_but_top_outermost(); + assert(all_but_top.size() >= 3); + assert(filesystem::path(all_but_top[0].source_file()).filename() == "test.cpp"sv); + assert(filesystem::path(all_but_top[1].source_file()).filename() == "test.cpp"sv); + assert(filesystem::path(all_but_top[2].source_file()).filename() == "test.cpp"sv); + + assert(all_but_top[0].source_line() == 35); + assert(all_but_top[1].source_line() == 39); + assert(all_but_top[2].source_line() == 43); + + assert(trim_past_plus(all_but_top[0].description()) == "P0881R7_stacktrace!all_but_top_inner"sv); + assert(trim_past_plus(all_but_top[1].description()) == "P0881R7_stacktrace!all_but_top_outer"sv); + assert(trim_past_plus(all_but_top[2].description()) == "P0881R7_stacktrace!all_but_top_outermost"sv); + + auto three_excluding_top = three_excluding_top_outermost(); + assert(three_excluding_top.size() == 3); + assert(filesystem::path(three_excluding_top[0].source_file()).filename() == "test.cpp"sv); + assert(filesystem::path(three_excluding_top[1].source_file()).filename() == "test.cpp"sv); + assert(filesystem::path(three_excluding_top[2].source_file()).filename() == "test.cpp"sv); + + assert(three_excluding_top[0].source_line() == 51); + assert(three_excluding_top[1].source_line() == 55); + assert(three_excluding_top[2].source_line() == 59); + + assert(trim_past_plus(three_excluding_top[0].description()) == "P0881R7_stacktrace!three_excluding_top_inner"sv); + assert(trim_past_plus(three_excluding_top[1].description()) == "P0881R7_stacktrace!three_excluding_top_outer"sv); + assert( + trim_past_plus(three_excluding_top[2].description()) == "P0881R7_stacktrace!three_excluding_top_outermost"sv); + + + try { + (void) all.at(all.size()); + assert(false); // should have thrown + } catch (out_of_range) { + } + + auto all_copy = all; + + assert(all == all_copy); + assert(all != all_but_top); + assert(all > all_but_top); + assert(three_excluding_top < all_but_top); + + assert((all <=> all_copy) == std::strong_ordering::equal); + assert((all <=> all_but_top) == std::strong_ordering::greater); + assert((three_excluding_top <=> all_but_top) == std::strong_ordering::less); + + assert(std::hash{}(all) == std::hash{}(all_copy)); + assert(std::hash{}(all[0]) == std::hash{}(all_copy[0])); + + assert(!all.empty()); + assert(std::distance(all.begin(), all.end()) == static_cast(all.size())); + assert(std::distance(all.rbegin(), all.rend()) == static_cast(all.size())); + assert(std::distance(all.cbegin(), all.cend()) == static_cast(all.size())); + assert(std::distance(all.crbegin(), all.crend()) == static_cast(all.size())); + + stacktrace empty_trace; + assert(empty_trace.size() == 0); + assert(empty_trace.begin() == empty_trace.end()); + assert(empty_trace.rbegin() == empty_trace.rend()); + assert(empty_trace.cbegin() == empty_trace.cend()); + assert(empty_trace.crbegin() == empty_trace.crend()); + + stacktrace_entry empty_entry; + assert(empty_entry.description() == ""sv); + assert(empty_entry.source_file() == ""sv); + assert(empty_entry.source_line() == 0); + + auto s = to_string_using_low_level_members(all); + assert(s == to_string_using_stream_entry(all)); + assert(s == to_string_using_stream(all)); + assert(s == to_string_using_to_string_entry(all)); + assert(s == to_string_using_to_string(all)); +} From ab5f1e9612aa3f8781963b3c861dc9c742e6fd11 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 15:54:31 +0200 Subject: [PATCH 052/131] we are the std --- tests/std/tests/P0881R7_stacktrace/test.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index a1e7fbc9a6..8487210718 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -166,18 +166,18 @@ int main() { assert(all > all_but_top); assert(three_excluding_top < all_but_top); - assert((all <=> all_copy) == std::strong_ordering::equal); - assert((all <=> all_but_top) == std::strong_ordering::greater); - assert((three_excluding_top <=> all_but_top) == std::strong_ordering::less); + assert((all <=> all_copy) == strong_ordering::equal); + assert((all <=> all_but_top) == strong_ordering::greater); + assert((three_excluding_top <=> all_but_top) == strong_ordering::less); - assert(std::hash{}(all) == std::hash{}(all_copy)); - assert(std::hash{}(all[0]) == std::hash{}(all_copy[0])); + assert(hash{}(all) == hash{}(all_copy)); + assert(hash{}(all[0]) == hash{}(all_copy[0])); assert(!all.empty()); - assert(std::distance(all.begin(), all.end()) == static_cast(all.size())); - assert(std::distance(all.rbegin(), all.rend()) == static_cast(all.size())); - assert(std::distance(all.cbegin(), all.cend()) == static_cast(all.size())); - assert(std::distance(all.crbegin(), all.crend()) == static_cast(all.size())); + assert(distance(all.begin(), all.end()) == static_cast(all.size())); + assert(distance(all.rbegin(), all.rend()) == static_cast(all.size())); + assert(distance(all.cbegin(), all.cend()) == static_cast(all.size())); + assert(distance(all.crbegin(), all.crend()) == static_cast(all.size())); stacktrace empty_trace; assert(empty_trace.size() == 0); From 631f375259ebb402ec39dee3866c2733b3721a0f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 15:55:03 +0200 Subject: [PATCH 053/131] -newline --- tests/std/tests/P0881R7_stacktrace/test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index 8487210718..edc5f60de6 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -152,7 +152,6 @@ int main() { assert( trim_past_plus(three_excluding_top[2].description()) == "P0881R7_stacktrace!three_excluding_top_outermost"sv); - try { (void) all.at(all.size()); assert(false); // should have thrown From 284f96baf3a94807611410ed3106bd73173b3bf2 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 15:57:38 +0200 Subject: [PATCH 054/131] _STACKSTRACE_ --- stl/inc/stacktrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index d2b8f93d75..5f4f940baa 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -342,4 +342,4 @@ _STL_RESTORE_CLANG_WARNINGS #endif // ^^^ _HAS_CXX23 ^^^ #endif // _STL_COMPILER_PREPROCESSOR -#endif // _STACK_ +#endif // _STACKSTRACE_ From 762f72d52165a00381bf8a45ddc29ca2d00abd80 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 16:20:09 +0200 Subject: [PATCH 055/131] unnecessary void return --- stl/inc/stacktrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 5f4f940baa..e9a77aedf8 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -290,7 +290,7 @@ using stacktrace = basic_stacktrace>; template void swap(basic_stacktrace<_Al>& _Ax, basic_stacktrace<_Al>& _Bx) noexcept(noexcept(_Ax.swap(_Bx))) { - return _Ax.swap(_Bx); + _Ax.swap(_Bx); } [[nodiscard]] inline string to_string(const stacktrace_entry& _Fx) { From b5c76244d707d203cb20225c3848451f2a1969e4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 16:46:33 +0200 Subject: [PATCH 056/131] error safety on initialization --- stl/src/stacktrace.cpp | 60 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index eba164e545..10a4244248 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -53,6 +53,34 @@ namespace { bool initialize_attempted = false; SRWLOCK srw = SRWLOCK_INIT; + void uninitialize() { + srw_lock_guard lock{srw}; + + // "Phoenix singleton" - destroy and set to null, so that can initialize later again + + if (debug_client != nullptr) { + if (attached) { + debug_client->DetachProcesses(); + attached = false; + } + + debug_client->Release(); + debug_client = nullptr; + } + + if (debug_control != nullptr) { + debug_control->Release(); + debug_control = nullptr; + } + + if (debug_symbols != nullptr) { + debug_symbols->Release(); + debug_symbols = nullptr; + } + + initialize_attempted = false; + } + bool try_initialize() { if (!initialize_attempted) { // Deliberately not calling CoInitialize[Ex] @@ -70,33 +98,10 @@ namespace { } } - atexit([] { - srw_lock_guard lock{srw}; - - // "Phoenix singleton" - destroy and set to null, so that can initialize later again - - if (debug_client != nullptr) { - if (attached) { - debug_client->DetachProcesses(); - attached = false; - } - - debug_client->Release(); - debug_client = nullptr; - } - - if (debug_control != nullptr) { - debug_control->Release(); - debug_control = nullptr; - } - - if (debug_symbols != nullptr) { - debug_symbols->Release(); - debug_symbols = nullptr; - } - - initialize_attempted = false; - }); + if (atexit(uninitialize) != 0) { + uninitialize(); + return false; + } initialize_attempted = true; @@ -215,7 +220,6 @@ namespace { return get_description(address, str, off, fill); } - } // namespace _EXTERN_C From 991fb2a1c6d3f53c6b326ffac6d1a42c958f1d0f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 20:24:51 +0200 Subject: [PATCH 057/131] Load modules from the binaries dir. Thanks @ben-craig --- stl/CMakeLists.txt | 10 +++--- stl/inc/stacktrace | 2 +- stl/src/stacktrace.cpp | 75 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 7e677a0d6d..efc31c8f26 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -458,7 +458,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_eha_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHa") add_library(msvcp${D_SUFFIX} SHARED) - target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects msvcp${D_SUFFIX}_init_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") + target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects msvcp${D_SUFFIX}_init_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib" "Shlwapi.lib") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_base${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -479,7 +479,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp_1${D_SUFFIX}_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp_1${D_SUFFIX} SHARED) - target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") + target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib" "Shlwapi.lib") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -492,7 +492,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_link_libraries(msvcp_2${D_SUFFIX}_objects PRIVATE Boost::math) add_library(msvcp_2${D_SUFFIX} SHARED) - target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") + target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib" "Shlwapi.lib") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -514,7 +514,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO file(WRITE "${_ATOMIC_WAIT_DEF_NAME}" "${_ATOMIC_WAIT_DEF_CONTENTS}") add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${_ATOMIC_WAIT_DEF_NAME}") - target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "DbgEng.lib") + target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "DbgEng.lib" "Shlwapi.lib") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "${_ATOMIC_WAIT_OUTPUT_NAME}") @@ -526,7 +526,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp${D_SUFFIX}_codecvt_ids SHARED) - target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib") + target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib" "Shlwapi.lib") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_codecvt_ids${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_codecvt_ids${VCLIBS_SUFFIX}") diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index e9a77aedf8..660ca426cd 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -65,7 +65,7 @@ void __stdcall __std_stacktrace_description( void __stdcall __std_stacktrace_source_file( const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) noexcept; +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) noexcept(false); void __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill) noexcept(false); diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 10a4244248..468f87f4b3 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -7,13 +7,16 @@ // In particular, basic_string must not be included here. #include +#include // clang-format off #include // should be before any header that includes #include +#include // clang-format on #pragma comment(lib, "DbgEng.lib") +#pragma comment(lib, "Shlwapi.lib") // The below function pointer types be in sync with @@ -46,12 +49,13 @@ namespace { SRWLOCK* const locked; }; - IDebugClient* debug_client = nullptr; - IDebugSymbols* debug_symbols = nullptr; - IDebugControl* debug_control = nullptr; - bool attached = false; - bool initialize_attempted = false; - SRWLOCK srw = SRWLOCK_INIT; + IDebugClient* debug_client = nullptr; + IDebugSymbols* debug_symbols = nullptr; + IDebugSymbols3* debug_symbols3 = nullptr; + IDebugControl* debug_control = nullptr; + bool attached = false; + bool initialize_attempted = false; + SRWLOCK srw = SRWLOCK_INIT; void uninitialize() { srw_lock_guard lock{srw}; @@ -95,6 +99,9 @@ namespace { if (attached) { debug_control->WaitForEvent(0, INFINITE); } + + // If this failes, will use IDebugSymbols + debug_symbols->QueryInterface(IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); } } @@ -108,6 +115,54 @@ namespace { return debug_symbols != nullptr; } + void ensure_module_symbols_loaded_from_current_dir(const void* const address) { + ULONG index = 0; + ULONG64 base = 0; + if (FAILED(debug_symbols->GetModuleByOffset(reinterpret_cast(address), 0, &index, &base))) { + return; + } + + DEBUG_MODULE_PARAMETERS params; + if (FAILED(debug_symbols->GetModuleParameters(1, &base, index, ¶ms))) { + return; + } + + if (params.SymbolType != DEBUG_SYMTYPE_DEFERRED) { + return; + } + + if (debug_symbols3) { + ULONG wide_name_size = 0; + + if (FAILED(debug_symbols3->GetModuleNameStringWide( + DEBUG_MODNAME_IMAGE, index, base, nullptr, 0, &wide_name_size))) { + return; + } + + auto image_path = std::make_unique(wide_name_size); + + if (debug_symbols3->GetModuleNameStringWide( + DEBUG_MODNAME_IMAGE, index, base, image_path.get(), wide_name_size, nullptr) != S_OK) { + return; + } + + PathRemoveFileSpecW(image_path.get()); + + debug_symbols3->AppendSymbolPathWide(image_path.get()); + } else { + auto image_path = std::make_unique(params.ImageNameSize); + + if (FAILED(debug_symbols->GetModuleNames(index, base, image_path.get(), params.ImageNameSize, nullptr, + nullptr, 0, nullptr, nullptr, 0, nullptr))) { + return; + } + + PathRemoveFileSpecA(image_path.get()); + + debug_symbols->AppendSymbolPath(image_path.get()); + } + } + size_t get_description(const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { if (!try_initialize()) { return 0; @@ -118,6 +173,8 @@ namespace { HRESULT hr = E_UNEXPECTED; ULONG64 displacement = 0; + ensure_module_symbols_loaded_from_current_dir(address); + for (;;) { ULONG new_size = 0; @@ -156,6 +213,8 @@ namespace { return 0; } + ensure_module_symbols_loaded_from_current_dir(address); + // Initially pass the current capacity, will retry with bigger buffer if fails. size_t size = fill(0, str, nullptr, nullptr) - off; HRESULT hr = E_UNEXPECTED; @@ -193,6 +252,8 @@ namespace { return 0; } + ensure_module_symbols_loaded_from_current_dir(address); + ULONG line = 0; if (FAILED(debug_symbols->GetLineByOffset( @@ -247,7 +308,7 @@ void __stdcall __std_stacktrace_source_file( source_file(_Address, _Str, 0, nullptr, _Fill); } -unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { +unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept(false) { const srw_lock_guard lock{srw}; return source_line(_Address); From fa99f51a45a486abcfde043efe3e1c637064ac21 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 20:30:39 +0200 Subject: [PATCH 058/131] clang format --- stl/src/stacktrace.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 468f87f4b3..bce3320ce9 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -116,7 +116,7 @@ namespace { } void ensure_module_symbols_loaded_from_current_dir(const void* const address) { - ULONG index = 0; + ULONG index = 0; ULONG64 base = 0; if (FAILED(debug_symbols->GetModuleByOffset(reinterpret_cast(address), 0, &index, &base))) { return; @@ -136,13 +136,14 @@ namespace { if (FAILED(debug_symbols3->GetModuleNameStringWide( DEBUG_MODNAME_IMAGE, index, base, nullptr, 0, &wide_name_size))) { - return; + return; } auto image_path = std::make_unique(wide_name_size); - + if (debug_symbols3->GetModuleNameStringWide( - DEBUG_MODNAME_IMAGE, index, base, image_path.get(), wide_name_size, nullptr) != S_OK) { + DEBUG_MODNAME_IMAGE, index, base, image_path.get(), wide_name_size, nullptr) + != S_OK) { return; } @@ -158,7 +159,7 @@ namespace { } PathRemoveFileSpecA(image_path.get()); - + debug_symbols->AppendSymbolPath(image_path.get()); } } From 9675d08b24ac19600b2bc33b4a5a50d1a84794bb Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 20:37:31 +0200 Subject: [PATCH 059/131] add escape hatch to alter interface properties --- stl/inc/stacktrace | 2 ++ stl/src/stacktrace.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 660ca426cd..780519f5f2 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -69,6 +69,8 @@ void __stdcall __std_stacktrace_source_file( void __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill) noexcept(false); + +[[nodiscard]] void* __stdcall __std_stacktrace_get_debug_interface() noexcept; // clang-format on _END_EXTERN_C diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index bce3320ce9..2b444e8c10 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -340,4 +340,14 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si off = address_to_string(data[i], _Str, off, _Fill); } } + +[[nodiscard]] void* __stdcall __std_stacktrace_get_debug_interface() noexcept { + const srw_lock_guard lock{srw}; + + if (!try_initialize()) { + return nullptr; + } + + return debug_symbols; +} _END_EXTERN_C From 671993b34258e17ba419396b1ea5b2b22a422443 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 20:47:25 +0200 Subject: [PATCH 060/131] move initialization to avoid unnecessary attempts --- stl/src/stacktrace.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 2b444e8c10..ba50c411df 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -165,10 +165,6 @@ namespace { } size_t get_description(const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { - if (!try_initialize()) { - return 0; - } - // Initially pass the current capacity, will retry with bigger buffer if fails. size_t size = fill(0, str, nullptr, nullptr) - off; HRESULT hr = E_UNEXPECTED; @@ -210,10 +206,6 @@ namespace { size_t source_file( const void* const address, void* const str, size_t off, ULONG* const line, const _Stacktrace_string_fill fill) { - if (!try_initialize()) { - return 0; - } - ensure_module_symbols_loaded_from_current_dir(address); // Initially pass the current capacity, will retry with bigger buffer if fails. @@ -249,10 +241,6 @@ namespace { } [[nodiscard]] unsigned source_line(const void* const address) { - if (!try_initialize()) { - return 0; - } - ensure_module_symbols_loaded_from_current_dir(address); ULONG line = 0; @@ -299,12 +287,20 @@ void __stdcall __std_stacktrace_description( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; + if (!try_initialize()) { + return; + } + get_description(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_source_file( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; + + if (!try_initialize()) { + return; + } source_file(_Address, _Str, 0, nullptr, _Fill); } @@ -312,6 +308,10 @@ void __stdcall __std_stacktrace_source_file( unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept(false) { const srw_lock_guard lock{srw}; + if (!try_initialize()) { + return; + } + return source_line(_Address); } @@ -319,6 +319,10 @@ void __stdcall __std_stacktrace_address_to_string( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; + if (!try_initialize()) { + return; + } + address_to_string(_Address, _Str, 0, _Fill); } @@ -326,6 +330,10 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; + if (!try_initialize()) { + return; + } + const auto data = reinterpret_cast(_Addresses); size_t off = 0; From 94c6d1d92e6242cf44b0a49368c0cbc91dc6ec55 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 20:51:47 +0200 Subject: [PATCH 061/131] move ensure_module_symbols_loaded_from_current_dir to avoid unnecessary attempts --- stl/src/stacktrace.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index ba50c411df..574830b5ae 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -170,8 +170,6 @@ namespace { HRESULT hr = E_UNEXPECTED; ULONG64 displacement = 0; - ensure_module_symbols_loaded_from_current_dir(address); - for (;;) { ULONG new_size = 0; @@ -206,8 +204,6 @@ namespace { size_t source_file( const void* const address, void* const str, size_t off, ULONG* const line, const _Stacktrace_string_fill fill) { - ensure_module_symbols_loaded_from_current_dir(address); - // Initially pass the current capacity, will retry with bigger buffer if fails. size_t size = fill(0, str, nullptr, nullptr) - off; HRESULT hr = E_UNEXPECTED; @@ -241,8 +237,6 @@ namespace { } [[nodiscard]] unsigned source_line(const void* const address) { - ensure_module_symbols_loaded_from_current_dir(address); - ULONG line = 0; if (FAILED(debug_symbols->GetLineByOffset( @@ -290,6 +284,8 @@ void __stdcall __std_stacktrace_description( if (!try_initialize()) { return; } + + ensure_module_symbols_loaded_from_current_dir(_Address); get_description(_Address, _Str, 0, _Fill); } @@ -302,6 +298,8 @@ void __stdcall __std_stacktrace_source_file( return; } + ensure_module_symbols_loaded_from_current_dir(_Address); + source_file(_Address, _Str, 0, nullptr, _Fill); } @@ -312,6 +310,8 @@ unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noex return; } + ensure_module_symbols_loaded_from_current_dir(_Address); + return source_line(_Address); } @@ -323,6 +323,8 @@ void __stdcall __std_stacktrace_address_to_string( return; } + ensure_module_symbols_loaded_from_current_dir(_Address); + address_to_string(_Address, _Str, 0, _Fill); } @@ -345,6 +347,9 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si return sz; }); } + + ensure_module_symbols_loaded_from_current_dir(data[i]); + off = address_to_string(data[i], _Str, off, _Fill); } } From fde7ac3ac566a2a07a4215378b635be8a5b33696 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 20:55:23 +0200 Subject: [PATCH 062/131] clang format --- stl/src/stacktrace.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 574830b5ae..609cff10ca 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -284,7 +284,7 @@ void __stdcall __std_stacktrace_description( if (!try_initialize()) { return; } - + ensure_module_symbols_loaded_from_current_dir(_Address); get_description(_Address, _Str, 0, _Fill); @@ -293,7 +293,7 @@ void __stdcall __std_stacktrace_description( void __stdcall __std_stacktrace_source_file( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; - + if (!try_initialize()) { return; } From 93d4f1cc3d53dfe9bd92a6b4a3c7c5ce31de9256 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 20:59:29 +0200 Subject: [PATCH 063/131] 0 --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 609cff10ca..ea5cf826f4 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -307,7 +307,7 @@ unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noex const srw_lock_guard lock{srw}; if (!try_initialize()) { - return; + return 0; } ensure_module_symbols_loaded_from_current_dir(_Address); From 0cf831dcda54039d5adf158ad114a8a6f27d24e1 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 21:37:54 +0200 Subject: [PATCH 064/131] fallback testing as suggested by @ben-craig Three modes: * With full debug info * Without debug info, but with exports * Without both debug info and exports --- tests/std/tests/P0881R7_stacktrace/env.lst | 4 +- tests/std/tests/P0881R7_stacktrace/test.cpp | 109 +++++++++++++++----- 2 files changed, 89 insertions(+), 24 deletions(-) diff --git a/tests/std/tests/P0881R7_stacktrace/env.lst b/tests/std/tests/P0881R7_stacktrace/env.lst index 6abf6509cc..73e14d5ef4 100644 --- a/tests/std/tests/P0881R7_stacktrace/env.lst +++ b/tests/std/tests/P0881R7_stacktrace/env.lst @@ -3,4 +3,6 @@ RUNALL_INCLUDE ..\usual_latest_matrix.lst RUNALL_CROSSLIST -PM_CL="/Zi" +PM_CL="/Zi /DHAS_DEBUG_INFO" +PM_CL="/DHAS_EXPORT" +PM_CL="" diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index edc5f60de6..91346fb9e0 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -7,55 +7,61 @@ #include #include +#ifdef HAS_EXPORT +#define MAYBE_EXPORT __declspec(dllexport) +#else // ^^^ HAS_EXPORT ^^^ / vvv !HAS_EXPORT vvv +#define MAYBE_EXPORT +#endif // ^^^ !HAS_EXPORT ^^^ + using namespace std; // Note: the bellow assumes tail call optimization disabled, which is in case in /Od -stacktrace all_innermost() { +MAYBE_EXPORT stacktrace all_innermost() { return stacktrace::current(); } -stacktrace all_inner() { +MAYBE_EXPORT stacktrace all_inner() { return all_innermost(); } -stacktrace all_outer() { +MAYBE_EXPORT stacktrace all_outer() { return all_inner(); } -stacktrace all_outermost() { +MAYBE_EXPORT stacktrace all_outermost() { return all_outer(); } -stacktrace all_but_top_innermost() { +MAYBE_EXPORT stacktrace all_but_top_innermost() { return stacktrace::current(1); } -stacktrace all_but_top_inner() { +MAYBE_EXPORT stacktrace all_but_top_inner() { return all_but_top_innermost(); } -stacktrace all_but_top_outer() { +MAYBE_EXPORT stacktrace all_but_top_outer() { return all_but_top_inner(); } -stacktrace all_but_top_outermost() { +MAYBE_EXPORT stacktrace all_but_top_outermost() { return all_but_top_outer(); } -stacktrace three_excluding_top_innermost() { +MAYBE_EXPORT stacktrace three_excluding_top_innermost() { return stacktrace::current(1, 3); } -stacktrace three_excluding_top_inner() { +MAYBE_EXPORT stacktrace three_excluding_top_inner() { return three_excluding_top_innermost(); } -stacktrace three_excluding_top_outer() { +MAYBE_EXPORT stacktrace three_excluding_top_outer() { return three_excluding_top_inner(); } -stacktrace three_excluding_top_outermost() { +MAYBE_EXPORT stacktrace three_excluding_top_outermost() { return three_excluding_top_outer(); } @@ -104,53 +110,110 @@ string to_string_using_to_string(const stacktrace& st) { return to_string(st) + "\n"; } +#if defined(HAS_DEBUG_INFO) || defined(HAS_EXPORT) +#define HAS_NAMES +#endif // ^^^ defined(HAS_DEBUG_INFO) || defined(HAS_EXPORT) ^^^ int main() { auto all = all_outermost(); assert(all.size() >= 4); + +#ifdef HAS_DEBUG_INFO assert(filesystem::path(all.at(0).source_file()).filename() == "test.cpp"sv); assert(filesystem::path(all.at(1).source_file()).filename() == "test.cpp"sv); assert(filesystem::path(all.at(2).source_file()).filename() == "test.cpp"sv); assert(filesystem::path(all.at(3).source_file()).filename() == "test.cpp"sv); - assert(all.at(0).source_line() == 15); - assert(all.at(1).source_line() == 19); - assert(all.at(2).source_line() == 23); - assert(all.at(3).source_line() == 27); - + assert(all.at(0).source_line() == 21); + assert(all.at(1).source_line() == 25); + assert(all.at(2).source_line() == 29); + assert(all.at(3).source_line() == 33); +#else // ^^^ HAS_DEBUG_INFO ^^^ / vvv !HAS_DEBUG_INFO vvv + assert(filesystem::path(all.at(0).source_file()).filename() == ""sv); + assert(filesystem::path(all.at(1).source_file()).filename() == ""sv); + assert(filesystem::path(all.at(2).source_file()).filename() == ""sv); + assert(filesystem::path(all.at(3).source_file()).filename() == ""sv); + + assert(all.at(0).source_line() == 0); + assert(all.at(1).source_line() == 0); + assert(all.at(2).source_line() == 0); + assert(all.at(3).source_line() == 0); +#endif // ^^^ !HAS_DEBUG_INFO ^^^ + +#ifdef HAS_NAMES assert(trim_past_plus(all.at(0).description()) == "P0881R7_stacktrace!all_innermost"sv); assert(trim_past_plus(all.at(1).description()) == "P0881R7_stacktrace!all_inner"sv); assert(trim_past_plus(all.at(2).description()) == "P0881R7_stacktrace!all_outer"sv); assert(trim_past_plus(all.at(3).description()) == "P0881R7_stacktrace!all_outermost"sv); +#else // ^^^ HAS_NAMES ^^^ / vvv !HAS_NAMES vvv + assert(trim_past_plus(all.at(0).description()) == "P0881R7_stacktrace"sv); + assert(trim_past_plus(all.at(1).description()) == "P0881R7_stacktrace"sv); + assert(trim_past_plus(all.at(2).description()) == "P0881R7_stacktrace"sv); + assert(trim_past_plus(all.at(3).description()) == "P0881R7_stacktrace"sv); +#endif // ^^^ !HAS_NAMES ^^^ auto all_but_top = all_but_top_outermost(); assert(all_but_top.size() >= 3); + +#ifdef HAS_DEBUG_INFO assert(filesystem::path(all_but_top[0].source_file()).filename() == "test.cpp"sv); assert(filesystem::path(all_but_top[1].source_file()).filename() == "test.cpp"sv); assert(filesystem::path(all_but_top[2].source_file()).filename() == "test.cpp"sv); - assert(all_but_top[0].source_line() == 35); - assert(all_but_top[1].source_line() == 39); - assert(all_but_top[2].source_line() == 43); + assert(all_but_top[0].source_line() == 41); + assert(all_but_top[1].source_line() == 45); + assert(all_but_top[2].source_line() == 49); +#else // ^^^ HAS_DEBUG_INFO ^^^ / vvv !HAS_DEBUG_INFO vvv + assert(filesystem::path(all_but_top[0].source_file()).filename() == ""sv); + assert(filesystem::path(all_but_top[1].source_file()).filename() == ""sv); + assert(filesystem::path(all_but_top[2].source_file()).filename() == ""sv); + assert(all_but_top[0].source_line() == 0); + assert(all_but_top[1].source_line() == 0); + assert(all_but_top[2].source_line() == 0); +#endif // ^^^ !HAS_DEBUG_INFO ^^^ + +#ifdef HAS_NAMES assert(trim_past_plus(all_but_top[0].description()) == "P0881R7_stacktrace!all_but_top_inner"sv); assert(trim_past_plus(all_but_top[1].description()) == "P0881R7_stacktrace!all_but_top_outer"sv); assert(trim_past_plus(all_but_top[2].description()) == "P0881R7_stacktrace!all_but_top_outermost"sv); +#else // ^^^ HAS_NAMES ^^^ / vvv !HAS_NAMES vvv + assert(trim_past_plus(all_but_top[0].description()) == "P0881R7_stacktrace"sv); + assert(trim_past_plus(all_but_top[1].description()) == "P0881R7_stacktrace"sv); + assert(trim_past_plus(all_but_top[2].description()) == "P0881R7_stacktrace"sv); +#endif // ^^^ !HAS_NAMES ^^^ auto three_excluding_top = three_excluding_top_outermost(); assert(three_excluding_top.size() == 3); +#ifdef HAS_DEBUG_INFO assert(filesystem::path(three_excluding_top[0].source_file()).filename() == "test.cpp"sv); assert(filesystem::path(three_excluding_top[1].source_file()).filename() == "test.cpp"sv); assert(filesystem::path(three_excluding_top[2].source_file()).filename() == "test.cpp"sv); - assert(three_excluding_top[0].source_line() == 51); - assert(three_excluding_top[1].source_line() == 55); - assert(three_excluding_top[2].source_line() == 59); + assert(three_excluding_top[0].source_line() == 57); + assert(three_excluding_top[1].source_line() == 61); + assert(three_excluding_top[2].source_line() == 65); +#else // ^^^ HAS_DEBUG_INFO ^^^ / vvv !HAS_DEBUG_INFO vvv + assert(filesystem::path(three_excluding_top[0].source_file()).filename() == ""sv); + assert(filesystem::path(three_excluding_top[1].source_file()).filename() == ""sv); + assert(filesystem::path(three_excluding_top[2].source_file()).filename() == ""sv); + + assert(three_excluding_top[0].source_line() == 0); + assert(three_excluding_top[1].source_line() == 0); + assert(three_excluding_top[2].source_line() == 0); +#endif // ^^^ !HAS_DEBUG_INFO ^^^ +#ifdef HAS_NAMES assert(trim_past_plus(three_excluding_top[0].description()) == "P0881R7_stacktrace!three_excluding_top_inner"sv); assert(trim_past_plus(three_excluding_top[1].description()) == "P0881R7_stacktrace!three_excluding_top_outer"sv); assert( trim_past_plus(three_excluding_top[2].description()) == "P0881R7_stacktrace!three_excluding_top_outermost"sv); +#else // ^^^ HAS_NAMES ^^^ / vvv !HAS_NAMES vvv + assert(trim_past_plus(three_excluding_top[0].description()) == "P0881R7_stacktrace"sv); + assert(trim_past_plus(three_excluding_top[1].description()) == "P0881R7_stacktrace"sv); + assert( + trim_past_plus(three_excluding_top[2].description()) == "P0881R7_stacktrace"sv); +#endif // ^^^ !HAS_NAMES ^^^ try { (void) all.at(all.size()); From d97d6dc8835f46f8519cc0a7a87d09e3a70a8d02 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 6 Feb 2022 22:35:28 +0200 Subject: [PATCH 065/131] clang format --- tests/std/tests/P0881R7_stacktrace/test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index 91346fb9e0..53a3ea5645 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -211,8 +211,7 @@ int main() { #else // ^^^ HAS_NAMES ^^^ / vvv !HAS_NAMES vvv assert(trim_past_plus(three_excluding_top[0].description()) == "P0881R7_stacktrace"sv); assert(trim_past_plus(three_excluding_top[1].description()) == "P0881R7_stacktrace"sv); - assert( - trim_past_plus(three_excluding_top[2].description()) == "P0881R7_stacktrace"sv); + assert(trim_past_plus(three_excluding_top[2].description()) == "P0881R7_stacktrace"sv); #endif // ^^^ !HAS_NAMES ^^^ try { From caebf993348ff4921a4233e7c28a651bede71beb Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 7 Feb 2022 10:36:42 +0200 Subject: [PATCH 066/131] nothrowing string alloc; symbol options --- stl/inc/stacktrace | 2 +- stl/src/stacktrace.cpp | 64 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 780519f5f2..5ca8c2e0c8 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -65,7 +65,7 @@ void __stdcall __std_stacktrace_description( void __stdcall __std_stacktrace_source_file( const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) noexcept(false); +[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) noexcept; void __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill) noexcept(false); diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index ea5cf826f4..405ee14aae 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -102,6 +102,29 @@ namespace { // If this failes, will use IDebugSymbols debug_symbols->QueryInterface(IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); + + // clang-format off + constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ | + 0x2 /* SYMOPT_UNDNAME */ | + 0x4 /* SYMOPT_DEFERRED_LOADS */ | + 0x10 /* SYMOPT_LOAD_LINES */ | + 0x20 /* SYMOPT_OMAP_FIND_NEAREST */ | + 0x100 /* SYMOPT_FAIL_CRITICAL_ERRORS */ | + 0x10000 /* SYMOPT_AUTO_PUBLICS */ | + 0x80000 /* SYMOPT_NO_PROMPTS */; + + constexpr ULONG remove_options = 0x8 /* SYMOPT_NO_CPP */ | + 0x40 /* SYMOPT_LOAD_ANYTHING */ | + 0x100 /* SYMOPT_NO_UNQUALIFIED_LOADS */ | + 0x400 /* SYMOPT_EXACT_SYMBOLS */ | + 0x1000 /* SYMOPT_IGNORE_NT_SYMPATH */ | + 0x4000 /* SYMOPT_PUBLICS_ONLY */ | + 0x8000 /* SYMOPT_NO_PUBLICS */ | + 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; + // clang-format on + + debug_symbols->AddSymbolOptions(add_options); + debug_symbols->RemoveSymbolOptions(remove_options); } } @@ -115,7 +138,14 @@ namespace { return debug_symbols != nullptr; } - void ensure_module_symbols_loaded_from_current_dir(const void* const address) { + // Temporarily alters symbol search path to search next to the current module + void module_symbols_load_from_module_dir(const void* const address) { + struct free_deleter { + void operator()(void* p) { + free(p); + } + }; + ULONG index = 0; ULONG64 base = 0; if (FAILED(debug_symbols->GetModuleByOffset(reinterpret_cast(address), 0, &index, &base))) { @@ -139,19 +169,29 @@ namespace { return; } - auto image_path = std::make_unique(wide_name_size); + std::unique_ptr image_path_wide( + static_cast(malloc(wide_name_size * sizeof(wchar_t)))); + + if (!image_path_wide) { + return; + } if (debug_symbols3->GetModuleNameStringWide( - DEBUG_MODNAME_IMAGE, index, base, image_path.get(), wide_name_size, nullptr) + DEBUG_MODNAME_IMAGE, index, base, image_path_wide.get(), wide_name_size, nullptr) != S_OK) { return; } - PathRemoveFileSpecW(image_path.get()); + PathRemoveFileSpecW(image_path_wide.get()); - debug_symbols3->AppendSymbolPathWide(image_path.get()); + debug_symbols3->AppendSymbolPathWide(image_path_wide.get()); } else { - auto image_path = std::make_unique(params.ImageNameSize); + std::unique_ptr image_path( + static_cast(malloc(params.ImageNameSize * sizeof(char)))); + + if (!image_path) { + return; + } if (FAILED(debug_symbols->GetModuleNames(index, base, image_path.get(), params.ImageNameSize, nullptr, nullptr, 0, nullptr, nullptr, 0, nullptr))) { @@ -285,7 +325,7 @@ void __stdcall __std_stacktrace_description( return; } - ensure_module_symbols_loaded_from_current_dir(_Address); + module_symbols_load_from_module_dir(_Address); get_description(_Address, _Str, 0, _Fill); } @@ -298,19 +338,19 @@ void __stdcall __std_stacktrace_source_file( return; } - ensure_module_symbols_loaded_from_current_dir(_Address); + module_symbols_load_from_module_dir(_Address); source_file(_Address, _Str, 0, nullptr, _Fill); } -unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept(false) { +unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { const srw_lock_guard lock{srw}; if (!try_initialize()) { return 0; } - ensure_module_symbols_loaded_from_current_dir(_Address); + module_symbols_load_from_module_dir(_Address); return source_line(_Address); } @@ -323,7 +363,7 @@ void __stdcall __std_stacktrace_address_to_string( return; } - ensure_module_symbols_loaded_from_current_dir(_Address); + module_symbols_load_from_module_dir(_Address); address_to_string(_Address, _Str, 0, _Fill); } @@ -348,7 +388,7 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si }); } - ensure_module_symbols_loaded_from_current_dir(data[i]); + module_symbols_load_from_module_dir(data[i]); off = address_to_string(data[i], _Str, off, _Fill); } From cd851524e4427ace488797c898882438bd12cc15 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 7 Feb 2022 11:12:25 +0200 Subject: [PATCH 067/131] -white --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 405ee14aae..1a2618df11 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -112,7 +112,7 @@ namespace { 0x100 /* SYMOPT_FAIL_CRITICAL_ERRORS */ | 0x10000 /* SYMOPT_AUTO_PUBLICS */ | 0x80000 /* SYMOPT_NO_PROMPTS */; - + constexpr ULONG remove_options = 0x8 /* SYMOPT_NO_CPP */ | 0x40 /* SYMOPT_LOAD_ANYTHING */ | 0x100 /* SYMOPT_NO_UNQUALIFIED_LOADS */ | From 1493f9720cb240bb6b9c4957f5c8aa8120e69536 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 8 Feb 2022 12:43:47 +0200 Subject: [PATCH 068/131] entry number: Example: ``` 1> C:\Project\trace\st_try.cpp(8): P0881R7_stacktrace!innermost+0x9d 2> C:\Project\trace\st_try.cpp(13): P0881R7_stacktrace!inner+0x17 3> C:\Project\trace\st_try.cpp(17): P0881R7_stacktrace!outer+0x17 4> C:\Project\trace\st_try.cpp(21): P0881R7_stacktrace!outermost+0x17 5> C:\Project\trace\st_try.cpp(25): P0881R7_stacktrace!main+0x17 ``` --- stl/src/stacktrace.cpp | 7 ++++++- tests/std/tests/P0881R7_stacktrace/test.cpp | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 1a2618df11..074af6172b 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -380,7 +380,7 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si size_t off = 0; - for (std::size_t i = 0; i != _Size; ++i) { + for (size_t i = 0; i != _Size; ++i) { if (off != 0) { off = string_fill(_Fill, off + 1, _Str, [](char* s, size_t sz) { s[sz - 1] = '\n'; @@ -388,6 +388,11 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si }); } + constexpr size_t max_entry_num = std::size("65536> ") - 1; // maximum possible line number + + off = string_fill(_Fill, off + max_entry_num, _Str, + [off, i](char* s, size_t) { return std::format_to_n(s + off, max_entry_num, "{}> ", i + 1).out - s; }); + module_symbols_load_from_module_dir(data[i]); off = address_to_string(data[i], _Str, off, _Fill); diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index 53a3ea5645..f31f82fd7b 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -74,7 +74,10 @@ string trim_past_plus(string str) { string to_string_using_low_level_members(const stacktrace& st) { stringstream ss; + int n = 0; for (const auto& i : st) { + ++n; + ss << n << "> "; auto l = i.source_line(); if (l != 0) { ss << i.source_file() << "(" << l << "): "; @@ -86,7 +89,10 @@ string to_string_using_low_level_members(const stacktrace& st) { string to_string_using_stream_entry(const stacktrace& st) { stringstream ss; + int n = 0; for (const auto& i : st) { + ++n; + ss << n << "> "; ss << i << "\n"; } return ss.str(); @@ -94,7 +100,10 @@ string to_string_using_stream_entry(const stacktrace& st) { string to_string_using_to_string_entry(const stacktrace& st) { stringstream ss; + int n = 0; for (const auto& i : st) { + ++n; + ss << n << "> "; ss << to_string(i) << "\n"; } return ss.str(); From 9bbe0a91a33a27500ba9659d7d4835882af0fbf4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 8 Feb 2022 15:51:24 +0200 Subject: [PATCH 069/131] zer0-based --- stl/src/stacktrace.cpp | 2 +- tests/std/tests/P0881R7_stacktrace/test.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 074af6172b..b41a7df5c8 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -391,7 +391,7 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si constexpr size_t max_entry_num = std::size("65536> ") - 1; // maximum possible line number off = string_fill(_Fill, off + max_entry_num, _Str, - [off, i](char* s, size_t) { return std::format_to_n(s + off, max_entry_num, "{}> ", i + 1).out - s; }); + [off, i](char* s, size_t) { return std::format_to_n(s + off, max_entry_num, "{}> ", i).out - s; }); module_symbols_load_from_module_dir(data[i]); diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index f31f82fd7b..a8231076fe 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -76,8 +76,8 @@ string to_string_using_low_level_members(const stacktrace& st) { stringstream ss; int n = 0; for (const auto& i : st) { - ++n; ss << n << "> "; + ++n; auto l = i.source_line(); if (l != 0) { ss << i.source_file() << "(" << l << "): "; @@ -91,8 +91,8 @@ string to_string_using_stream_entry(const stacktrace& st) { stringstream ss; int n = 0; for (const auto& i : st) { - ++n; ss << n << "> "; + ++n; ss << i << "\n"; } return ss.str(); @@ -102,8 +102,8 @@ string to_string_using_to_string_entry(const stacktrace& st) { stringstream ss; int n = 0; for (const auto& i : st) { - ++n; ss << n << "> "; + ++n; ss << to_string(i) << "\n"; } return ss.str(); From 71c68d88e1c3a3d39a8322a0ac7248a68ac8f097 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 14 Feb 2022 10:11:44 +0200 Subject: [PATCH 070/131] add stacktrace to the new header --- .../tests/P1502R1_standard_library_header_units/custom_format.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py b/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py index 7008dab9de..36aae11647 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py +++ b/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py @@ -74,6 +74,7 @@ def getImportableCxxLibraryHeaders(): 'spanstream', 'sstream', 'stack', + 'stacktrace', 'stdexcept', 'stop_token', 'streambuf', From 7d5e487da8a68796cca88295abedda0dbfa758d7 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 18 Feb 2022 18:45:57 +0200 Subject: [PATCH 071/131] thread coverage --- tests/std/tests/P0881R7_stacktrace/test.cpp | 31 +++++++++++++-------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index a8231076fe..9872cd81ed 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef HAS_EXPORT #define MAYBE_EXPORT __declspec(dllexport) @@ -15,6 +16,8 @@ using namespace std; +const int base_line = __LINE__; + // Note: the bellow assumes tail call optimization disabled, which is in case in /Od MAYBE_EXPORT stacktrace all_innermost() { @@ -123,7 +126,7 @@ string to_string_using_to_string(const stacktrace& st) { #define HAS_NAMES #endif // ^^^ defined(HAS_DEBUG_INFO) || defined(HAS_EXPORT) ^^^ -int main() { +void test_impl() { auto all = all_outermost(); assert(all.size() >= 4); @@ -133,10 +136,10 @@ int main() { assert(filesystem::path(all.at(2).source_file()).filename() == "test.cpp"sv); assert(filesystem::path(all.at(3).source_file()).filename() == "test.cpp"sv); - assert(all.at(0).source_line() == 21); - assert(all.at(1).source_line() == 25); - assert(all.at(2).source_line() == 29); - assert(all.at(3).source_line() == 33); + assert(all.at(0).source_line() == base_line + 5); + assert(all.at(1).source_line() == base_line + 9); + assert(all.at(2).source_line() == base_line + 13); + assert(all.at(3).source_line() == base_line + 17); #else // ^^^ HAS_DEBUG_INFO ^^^ / vvv !HAS_DEBUG_INFO vvv assert(filesystem::path(all.at(0).source_file()).filename() == ""sv); assert(filesystem::path(all.at(1).source_file()).filename() == ""sv); @@ -169,9 +172,9 @@ int main() { assert(filesystem::path(all_but_top[1].source_file()).filename() == "test.cpp"sv); assert(filesystem::path(all_but_top[2].source_file()).filename() == "test.cpp"sv); - assert(all_but_top[0].source_line() == 41); - assert(all_but_top[1].source_line() == 45); - assert(all_but_top[2].source_line() == 49); + assert(all_but_top[0].source_line() == base_line + 25); + assert(all_but_top[1].source_line() == base_line + 29); + assert(all_but_top[2].source_line() == base_line + 33); #else // ^^^ HAS_DEBUG_INFO ^^^ / vvv !HAS_DEBUG_INFO vvv assert(filesystem::path(all_but_top[0].source_file()).filename() == ""sv); assert(filesystem::path(all_but_top[1].source_file()).filename() == ""sv); @@ -199,9 +202,9 @@ int main() { assert(filesystem::path(three_excluding_top[1].source_file()).filename() == "test.cpp"sv); assert(filesystem::path(three_excluding_top[2].source_file()).filename() == "test.cpp"sv); - assert(three_excluding_top[0].source_line() == 57); - assert(three_excluding_top[1].source_line() == 61); - assert(three_excluding_top[2].source_line() == 65); + assert(three_excluding_top[0].source_line() == base_line + 41); + assert(three_excluding_top[1].source_line() == base_line + 45); + assert(three_excluding_top[2].source_line() == base_line + 49); #else // ^^^ HAS_DEBUG_INFO ^^^ / vvv !HAS_DEBUG_INFO vvv assert(filesystem::path(three_excluding_top[0].source_file()).filename() == ""sv); assert(filesystem::path(three_excluding_top[1].source_file()).filename() == ""sv); @@ -267,3 +270,9 @@ int main() { assert(s == to_string_using_to_string_entry(all)); assert(s == to_string_using_to_string(all)); } + +int main() { + std::thread t{test_impl}; + test_impl(); + t.join(); +} \ No newline at end of file From f5392fdfbf7cc85e622ac2371ca241ff4ea2633d Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 18 Feb 2022 19:14:02 +0200 Subject: [PATCH 072/131] Update tests/std/tests/P0881R7_stacktrace/test.cpp Co-authored-by: Daniel Marshall --- tests/std/tests/P0881R7_stacktrace/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index 9872cd81ed..2fc1131e4c 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -275,4 +275,4 @@ int main() { std::thread t{test_impl}; test_impl(); t.join(); -} \ No newline at end of file +} From ae83a4e4c0c9ea5d5bca08f897e7bd6d55cb8c2c Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 18 Feb 2022 19:56:26 +0200 Subject: [PATCH 073/131] fix header units test --- .../importable_cxx_library_headers.jsonc | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P1502R1_standard_library_header_units/importable_cxx_library_headers.jsonc b/tests/std/tests/P1502R1_standard_library_header_units/importable_cxx_library_headers.jsonc index ea9dda8147..57bf291726 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/importable_cxx_library_headers.jsonc +++ b/tests/std/tests/P1502R1_standard_library_header_units/importable_cxx_library_headers.jsonc @@ -61,6 +61,7 @@ "spanstream", "sstream", "stack", + "stacktrace", "stdexcept", "stop_token", "streambuf", From baff31aa91f5c3505336659d9d72e2f8632e3ce8 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 18 Feb 2022 20:44:57 +0200 Subject: [PATCH 074/131] [[maybe_useless]] --- tests/std/tests/P0881R7_stacktrace/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index 2fc1131e4c..aab02dbd7f 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -16,7 +16,7 @@ using namespace std; -const int base_line = __LINE__; +[[maybe_unused]] const int base_line = __LINE__; // Note: the bellow assumes tail call optimization disabled, which is in case in /Od From f82720ea88c7bef169f119507867ec6e3cf55dca Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 11 Mar 2022 10:08:44 +0200 Subject: [PATCH 075/131] Update stl/inc/stacktrace Co-authored-by: Stephan T. Lavavej --- stl/inc/stacktrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 5ca8c2e0c8..6dd6ab54b0 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -53,7 +53,7 @@ _EXTERN_C unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash) noexcept; -// Some of these exports may throw (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) +// Some of these functions may throw (they would propagate bad_alloc potentially thrown from string::resize_and_overwrite) // clang-format off void __stdcall __std_stacktrace_address_to_string( From 8bb418a47e1c44579a7015ff618602a7e57a9fff Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 11 Mar 2022 10:40:38 +0200 Subject: [PATCH 076/131] Update stacktrace --- stl/inc/stacktrace | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 6dd6ab54b0..1d8c9e6a9d 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -53,7 +53,8 @@ _EXTERN_C unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, unsigned long _FramesToCapture, void** _BackTrace, unsigned long* _BackTraceHash) noexcept; -// Some of these functions may throw (they would propagate bad_alloc potentially thrown from string::resize_and_overwrite) +// Some of these functions may throw +// (they would propagate bad_alloc potentially thrown from string::resize_and_overwrite) // clang-format off void __stdcall __std_stacktrace_address_to_string( From d6f43d6564f4c6cd8c20c60fa6a99c35009de149 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 11 Mar 2022 19:39:38 +0200 Subject: [PATCH 077/131] some review comments --- stl/inc/stacktrace | 65 ++++++++++++++++++------------------ stl/src/msvcp_stacktrace.def | 10 ------ stl/src/stacktrace.cpp | 10 +++--- 3 files changed, 38 insertions(+), 47 deletions(-) delete mode 100644 stl/src/msvcp_stacktrace.def diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 1d8c9e6a9d..4a887403d0 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -4,8 +4,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once -#ifndef _STACKSTRACE_ -#define _STACKSTRACE_ +#ifndef _STACKTRACE_ +#define _STACKTRACE_ #include #if _STL_COMPILER_PREPROCESSOR @@ -25,57 +25,58 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -using _Stacktrace_string_fill_callback = size_t (*)(char*, size_t, void* _Context); +using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context); -using _Stacktrace_string_fill = size_t (*)(size_t, void* _String, void* _Context, _Stacktrace_string_fill_callback); - -inline size_t _Stacktrace_string_fill_impl( - const size_t _Size, void* const _String, void* const _Context, const _Stacktrace_string_fill_callback _Callback) { - if (_Callback) { - struct _Stacktrace_string_fill_op { - size_t operator()(char* _Data, size_t _Size) { - return _Callback(_Data, _Size, _Context); - } - - _Stacktrace_string_fill_callback _Callback; - void* _Context; - }; - - static_cast<_STD string*>(_String)->resize_and_overwrite( - _Size, _Stacktrace_string_fill_op{_Callback, _Context}); - return static_cast<_STD string*>(_String)->size(); - } else { - return static_cast<_STD string*>(_String)->capacity(); - } -} +using _Stacktrace_string_fill = size_t(__stdcall*)( + size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback); _EXTERN_C -unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, unsigned long _FramesToCapture, - void** _BackTrace, unsigned long* _BackTraceHash) noexcept; +unsigned short __stdcall __std_stacktrace_capture(unsigned long _Frames_to_skip, unsigned long _Frames_to_capture, + void** _Back_trace, unsigned long* _Back_trace_hash) noexcept; // Some of these functions may throw // (they would propagate bad_alloc potentially thrown from string::resize_and_overwrite) // clang-format off void __stdcall __std_stacktrace_address_to_string( - const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); + const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); void __stdcall __std_stacktrace_description( - const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); + const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); void __stdcall __std_stacktrace_source_file( - const void* _Address, void* _Str, _Stacktrace_string_fill) noexcept(false); + const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); -[[nodiscard]] unsigned __stdcall __std_stacktrace_source_line(const void* _Address) noexcept; +_NODISCARD unsigned int __stdcall __std_stacktrace_source_line(const void* _Address) noexcept; void __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill) noexcept(false); -[[nodiscard]] void* __stdcall __std_stacktrace_get_debug_interface() noexcept; +_NODISCARD void* __stdcall __std_stacktrace_get_debug_interface() noexcept; // clang-format on _END_EXTERN_C _STD_BEGIN +inline size_t __stdcall _Stacktrace_string_fill_impl( + const size_t _Size, void* const _String, void* const _Context, const _Stacktrace_string_fill_callback _Callback) { + if (_Callback) { + struct _Stacktrace_string_fill_op { + size_t operator()(char* _Data, size_t _Size) { + return _Callback(_Data, _Size, _Context); + } + + _Stacktrace_string_fill_callback _Callback; + void* _Context; + }; + + static_cast<_STD string*>(_String)->resize_and_overwrite( + _Size, _Stacktrace_string_fill_op{_Callback, _Context}); + return static_cast<_STD string*>(_String)->size(); + } else { + return static_cast<_STD string*>(_String)->capacity(); + } +} + class stacktrace_entry { public: using native_handle_type = void*; @@ -345,4 +346,4 @@ _STL_RESTORE_CLANG_WARNINGS #endif // ^^^ _HAS_CXX23 ^^^ #endif // _STL_COMPILER_PREPROCESSOR -#endif // _STACKSTRACE_ +#endif // _STACKTRACE_ diff --git a/stl/src/msvcp_stacktrace.def b/stl/src/msvcp_stacktrace.def deleted file mode 100644 index 98bf67a66e..0000000000 --- a/stl/src/msvcp_stacktrace.def +++ /dev/null @@ -1,10 +0,0 @@ -; Copyright (c) Microsoft Corporation. -; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -EXPORTS - __std_stacktrace_address_to_string - __std_stacktrace_capture - __std_stacktrace_description - __std_stacktrace_source_file - __std_stacktrace_source_line - __std_stacktrace_to_string diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index b41a7df5c8..e627a426ae 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -307,12 +307,12 @@ namespace { } // namespace _EXTERN_C -[[nodiscard]] unsigned short __stdcall __std_stacktrace_capture(unsigned long _FramesToSkip, - const unsigned long _FramesToCapture, void** const _BackTrace, unsigned long* const _BackTraceHash) noexcept { +[[nodiscard]] unsigned short __stdcall __std_stacktrace_capture(unsigned long _Frames_to_skip, + const unsigned long _Frames_to_capture, void** const _Back_trace, unsigned long* const _Back_trace_hash) noexcept { #ifdef _DEBUG - _FramesToSkip += 1; // compensate absense of tail call optimization here + _Frames_to_skip += 1; // compensate absense of tail call optimization here #endif - return CaptureStackBackTrace(_FramesToSkip, _FramesToCapture, _BackTrace, _BackTraceHash); + return CaptureStackBackTrace(_Frames_to_skip, _Frames_to_capture, _Back_trace, _Back_trace_hash); } // Some of these exports may throw (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) @@ -343,7 +343,7 @@ void __stdcall __std_stacktrace_source_file( source_file(_Address, _Str, 0, nullptr, _Fill); } -unsigned __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { +unsigned int __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { const srw_lock_guard lock{srw}; if (!try_initialize()) { From 3ac35ed0629a2dc0e0029bff9b239fa009c5d062 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 11 Mar 2022 20:57:28 +0200 Subject: [PATCH 078/131] some review comments - missed parts --- stl/inc/stacktrace | 6 +++--- stl/src/stacktrace.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 4a887403d0..0b74ef9d24 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -69,11 +69,11 @@ inline size_t __stdcall _Stacktrace_string_fill_impl( void* _Context; }; - static_cast<_STD string*>(_String)->resize_and_overwrite( + static_cast(_String)->resize_and_overwrite( _Size, _Stacktrace_string_fill_op{_Callback, _Context}); - return static_cast<_STD string*>(_String)->size(); + return static_cast(_String)->size(); } else { - return static_cast<_STD string*>(_String)->capacity(); + return static_cast(_String)->capacity(); } } diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index e627a426ae..dbc64beb30 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -20,9 +20,9 @@ // The below function pointer types be in sync with -using _Stacktrace_string_fill_callback = size_t (*)(char*, size_t, void* _Context); +using _Stacktrace_string_fill_callback = size_t (__stdcall*)(char*, size_t, void* _Context); -using _Stacktrace_string_fill = size_t (*)(size_t, void* _Str, void* _Context, _Stacktrace_string_fill_callback); +using _Stacktrace_string_fill = size_t (__stdcall*)(size_t, void* _Str, void* _Context, _Stacktrace_string_fill_callback); namespace { template From 730fa69a7e8ef9042f003729f017722def377ec6 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 11 Mar 2022 21:18:34 +0200 Subject: [PATCH 079/131] clang format --- stl/inc/stacktrace | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 0b74ef9d24..6223ac3fab 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -69,8 +69,7 @@ inline size_t __stdcall _Stacktrace_string_fill_impl( void* _Context; }; - static_cast(_String)->resize_and_overwrite( - _Size, _Stacktrace_string_fill_op{_Callback, _Context}); + static_cast(_String)->resize_and_overwrite(_Size, _Stacktrace_string_fill_op{_Callback, _Context}); return static_cast(_String)->size(); } else { return static_cast(_String)->capacity(); From c151a23a5e3bda6d3375f522b8b30ed637c6dcee Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 12 Mar 2022 08:30:42 +0200 Subject: [PATCH 080/131] clang format --- stl/src/stacktrace.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index dbc64beb30..46491d10b0 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -20,9 +20,10 @@ // The below function pointer types be in sync with -using _Stacktrace_string_fill_callback = size_t (__stdcall*)(char*, size_t, void* _Context); +using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char*, size_t, void* _Context); -using _Stacktrace_string_fill = size_t (__stdcall*)(size_t, void* _Str, void* _Context, _Stacktrace_string_fill_callback); +using _Stacktrace_string_fill = size_t(__stdcall*)( + size_t, void* _Str, void* _Context, _Stacktrace_string_fill_callback); namespace { template From 42d88b6bf9c8c5b54b6ae0647891ef53cab3eecd Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 12 Mar 2022 08:41:14 +0200 Subject: [PATCH 081/131] sort --- .../test.compile.pass.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 3b84c7afd4..32f3a347da 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1580,6 +1580,20 @@ STATIC_ASSERT(__cpp_lib_ssize == 201902L); #endif #endif +#if _HAS_CXX23 +#ifndef __cpp_lib_stacktrace +#error __cpp_lib_stacktrace is not defined +#elif __cpp_lib_stacktrace != 202011L +#error __cpp_lib_stacktrace is not 202011L +#else +STATIC_ASSERT(__cpp_lib_stacktrace == 202011L); +#endif +#else +#ifdef __cpp_lib_stacktrace +#error __cpp_lib_stacktrace is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_starts_ends_with #error __cpp_lib_starts_ends_with is not defined @@ -1608,20 +1622,6 @@ STATIC_ASSERT(__cpp_lib_stdatomic_h == 202011L); #endif #endif -#if _HAS_CXX23 -#ifndef __cpp_lib_stacktrace -#error __cpp_lib_stacktrace is not defined -#elif __cpp_lib_stacktrace != 202011L -#error __cpp_lib_stacktrace is not 202011L -#else -STATIC_ASSERT(__cpp_lib_stacktrace == 202011L); -#endif -#else -#ifdef __cpp_lib_stacktrace -#error __cpp_lib_stacktrace is defined -#endif -#endif - #if _HAS_CXX23 #ifndef __cpp_lib_string_contains #error __cpp_lib_string_contains is not defined From 85c76a1de68e18bf48c6f448ee6afe8d92fe32f0 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 12 Mar 2022 08:41:34 +0200 Subject: [PATCH 082/131] remove directory populating --- stl/src/stacktrace.cpp | 76 ------------------------------------------ 1 file changed, 76 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 46491d10b0..7cbc04650a 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -139,72 +139,6 @@ namespace { return debug_symbols != nullptr; } - // Temporarily alters symbol search path to search next to the current module - void module_symbols_load_from_module_dir(const void* const address) { - struct free_deleter { - void operator()(void* p) { - free(p); - } - }; - - ULONG index = 0; - ULONG64 base = 0; - if (FAILED(debug_symbols->GetModuleByOffset(reinterpret_cast(address), 0, &index, &base))) { - return; - } - - DEBUG_MODULE_PARAMETERS params; - if (FAILED(debug_symbols->GetModuleParameters(1, &base, index, ¶ms))) { - return; - } - - if (params.SymbolType != DEBUG_SYMTYPE_DEFERRED) { - return; - } - - if (debug_symbols3) { - ULONG wide_name_size = 0; - - if (FAILED(debug_symbols3->GetModuleNameStringWide( - DEBUG_MODNAME_IMAGE, index, base, nullptr, 0, &wide_name_size))) { - return; - } - - std::unique_ptr image_path_wide( - static_cast(malloc(wide_name_size * sizeof(wchar_t)))); - - if (!image_path_wide) { - return; - } - - if (debug_symbols3->GetModuleNameStringWide( - DEBUG_MODNAME_IMAGE, index, base, image_path_wide.get(), wide_name_size, nullptr) - != S_OK) { - return; - } - - PathRemoveFileSpecW(image_path_wide.get()); - - debug_symbols3->AppendSymbolPathWide(image_path_wide.get()); - } else { - std::unique_ptr image_path( - static_cast(malloc(params.ImageNameSize * sizeof(char)))); - - if (!image_path) { - return; - } - - if (FAILED(debug_symbols->GetModuleNames(index, base, image_path.get(), params.ImageNameSize, nullptr, - nullptr, 0, nullptr, nullptr, 0, nullptr))) { - return; - } - - PathRemoveFileSpecA(image_path.get()); - - debug_symbols->AppendSymbolPath(image_path.get()); - } - } - size_t get_description(const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { // Initially pass the current capacity, will retry with bigger buffer if fails. size_t size = fill(0, str, nullptr, nullptr) - off; @@ -326,8 +260,6 @@ void __stdcall __std_stacktrace_description( return; } - module_symbols_load_from_module_dir(_Address); - get_description(_Address, _Str, 0, _Fill); } @@ -339,8 +271,6 @@ void __stdcall __std_stacktrace_source_file( return; } - module_symbols_load_from_module_dir(_Address); - source_file(_Address, _Str, 0, nullptr, _Fill); } @@ -351,8 +281,6 @@ unsigned int __stdcall __std_stacktrace_source_line(const void* const _Address) return 0; } - module_symbols_load_from_module_dir(_Address); - return source_line(_Address); } @@ -364,8 +292,6 @@ void __stdcall __std_stacktrace_address_to_string( return; } - module_symbols_load_from_module_dir(_Address); - address_to_string(_Address, _Str, 0, _Fill); } @@ -394,8 +320,6 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si off = string_fill(_Fill, off + max_entry_num, _Str, [off, i](char* s, size_t) { return std::format_to_n(s + off, max_entry_num, "{}> ", i).out - s; }); - module_symbols_load_from_module_dir(data[i]); - off = address_to_string(data[i], _Str, off, _Fill); } } From f8e0a3066e071ddc9596801fc74f1f46c86c84ca Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 12 Mar 2022 09:00:23 +0200 Subject: [PATCH 083/131] header unit test --- .../P1502R1_standard_library_header_units/test.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp index 465ec86710..47047b8d6b 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp +++ b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp @@ -108,7 +108,8 @@ constexpr bool test_source_location() { return true; } -int main() { +__declspec(dllexport) // for test export main to have it named even without debug info + int main() { { puts("Testing ."); constexpr int arr[]{11, 0, 22, 0, 33, 0, 44, 0, 55}; @@ -759,6 +760,17 @@ int main() { assert(s.empty()); } + { + puts("Testing ."); + auto desc = stacktrace::current().at(0).description(); + if (auto pos = desc.find("!"); pos != string::npos) { + desc = desc.substr(pos + 1); + } + if (auto pos = desc.find("+"); pos != string::npos) { + desc.resize(pos); + } + assert(desc == "main"); + } { puts("Testing ."); bool caught_puppies = false; From be59a6149e30846c327da4f87df013a344c6dcc8 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 12 Mar 2022 09:32:49 +0200 Subject: [PATCH 084/131] more const --- stl/inc/stacktrace | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 6223ac3fab..8c40d8d1d3 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -227,11 +227,11 @@ public: return _Frames.max_size(); } - [[nodiscard]] const_reference operator[](size_type _Sx) const noexcept /* strengthened */ { + [[nodiscard]] const_reference operator[](const size_type _Sx) const noexcept /* strengthened */ { return _Frames[_Sx]; } - [[nodiscard]] const_reference at(size_type _Sx) const { + [[nodiscard]] const_reference at(const size_type _Sx) const { return _Frames.at(_Sx); } From e5a31b93001d4d9346074b435749353afc30604c Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Mon, 14 Mar 2022 09:45:37 +0200 Subject: [PATCH 085/131] _NODISCARD --- stl/inc/stacktrace | 64 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 8c40d8d1d3..c66af4696c 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -86,33 +86,33 @@ public: ~stacktrace_entry() = default; - [[nodiscard]] constexpr native_handle_type native_handle() const noexcept { + _NODISCARD constexpr native_handle_type native_handle() const noexcept { return _Address; } - [[nodiscard]] constexpr explicit operator bool() const noexcept { + _NODISCARD constexpr explicit operator bool() const noexcept { return _Address != nullptr; } - [[nodiscard]] string description() const { + _NODISCARD string description() const { string _Result; __std_stacktrace_description(_Address, &_Result, _Stacktrace_string_fill_impl); return _Result; } - [[nodiscard]] string source_file() const { + _NODISCARD string source_file() const { string _Result; __std_stacktrace_source_file(_Address, &_Result, _Stacktrace_string_fill_impl); return _Result; } - [[nodiscard]] uint_least32_t source_line() const { + _NODISCARD uint_least32_t source_line() const { return __std_stacktrace_source_line(_Address); } - [[nodiscard]] friend constexpr bool operator==(const stacktrace_entry&, const stacktrace_entry&) noexcept = default; + _NODISCARD friend constexpr bool operator==(const stacktrace_entry&, const stacktrace_entry&) noexcept = default; - [[nodiscard]] friend constexpr strong_ordering operator<=>( + _NODISCARD friend constexpr strong_ordering operator<=>( const stacktrace_entry&, const stacktrace_entry&) noexcept = default; private: @@ -139,7 +139,7 @@ public: // __declspec(noinline) to make the same behavior for debug and release. // We force the current function to be always noinline and add its frame to skipped. - [[nodiscard]] __declspec(noinline) static basic_stacktrace + _NODISCARD __declspec(noinline) static basic_stacktrace current(const allocator_type& _Alloc = allocator_type()) noexcept { basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Alloc); _Result._Frames.resize(__std_stacktrace_capture(1, static_cast(_Max_frames), @@ -147,7 +147,7 @@ public: return _Result; } - [[nodiscard]] __declspec(noinline) static basic_stacktrace + _NODISCARD __declspec(noinline) static basic_stacktrace current(size_type _Skip, const allocator_type& _Alloc = allocator_type()) noexcept { basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Alloc); _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), @@ -155,7 +155,7 @@ public: return _Result; } - [[nodiscard]] __declspec(noinline) static basic_stacktrace + _NODISCARD __declspec(noinline) static basic_stacktrace current(size_type _Skip, size_type _Max_depth, const allocator_type& _Alloc = allocator_type()) noexcept { basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Alloc); _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), @@ -179,69 +179,69 @@ public: ~basic_stacktrace() = default; - [[nodiscard]] allocator_type get_allocator() const noexcept { + _NODISCARD allocator_type get_allocator() const noexcept { return _Frames.get_allocator(); } - [[nodiscard]] const_iterator begin() const noexcept { + _NODISCARD const_iterator begin() const noexcept { return _Frames.cbegin(); } - [[nodiscard]] const_iterator end() const noexcept { + _NODISCARD const_iterator end() const noexcept { return _Frames.cend(); } - [[nodiscard]] const_reverse_iterator rbegin() const noexcept { + _NODISCARD const_reverse_iterator rbegin() const noexcept { return _Frames.crbegin(); } - [[nodiscard]] const_reverse_iterator rend() const noexcept { + _NODISCARD const_reverse_iterator rend() const noexcept { return _Frames.crend(); } - [[nodiscard]] const_iterator cbegin() const noexcept { + _NODISCARD const_iterator cbegin() const noexcept { return _Frames.cbegin(); } - [[nodiscard]] const_iterator cend() const noexcept { + _NODISCARD const_iterator cend() const noexcept { return _Frames.cend(); } - [[nodiscard]] const_reverse_iterator crbegin() const noexcept { + _NODISCARD const_reverse_iterator crbegin() const noexcept { return _Frames.crbegin(); } - [[nodiscard]] const_reverse_iterator crend() const noexcept { + _NODISCARD const_reverse_iterator crend() const noexcept { return _Frames.crend(); } - [[nodiscard]] bool empty() const noexcept { + _NODISCARD bool empty() const noexcept { return _Frames.empty(); } - [[nodiscard]] size_type size() const noexcept { + _NODISCARD size_type size() const noexcept { return _Frames.size(); } - [[nodiscard]] size_type max_size() const noexcept { + _NODISCARD size_type max_size() const noexcept { return _Frames.max_size(); } - [[nodiscard]] const_reference operator[](const size_type _Sx) const noexcept /* strengthened */ { + _NODISCARD const_reference operator[](const size_type _Sx) const noexcept /* strengthened */ { return _Frames[_Sx]; } - [[nodiscard]] const_reference at(const size_type _Sx) const { + _NODISCARD const_reference at(const size_type _Sx) const { return _Frames.at(_Sx); } template - [[nodiscard]] friend bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { + _NODISCARD friend bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { return _Lhs._Hash == _Rhs._Hash && _Lhs._Frames == _Rhs._Frames; } template - [[nodiscard]] friend strong_ordering operator<=>( + _NODISCARD friend strong_ordering operator<=>( const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { const auto _Result = _Lhs._Frames.size() <=> _Rhs._Frames.size(); if (_Result != strong_ordering::equal) { @@ -267,11 +267,11 @@ public: _STD swap(_Hash, _Other._Hash); } - [[nodiscard]] unsigned long _Get_hash() const noexcept { + _NODISCARD unsigned long _Get_hash() const noexcept { return _Hash; } - [[nodiscard]] const void* _Data() const noexcept { + _NODISCARD const void* _Data() const noexcept { return _Frames.data(); } @@ -296,14 +296,14 @@ void swap(basic_stacktrace<_Al>& _Ax, basic_stacktrace<_Al>& _Bx) noexcept(noexc _Ax.swap(_Bx); } -[[nodiscard]] inline string to_string(const stacktrace_entry& _Fx) { +_NODISCARD inline string to_string(const stacktrace_entry& _Fx) { string _Result; __std_stacktrace_address_to_string(_Fx.native_handle(), &_Result, _Stacktrace_string_fill_impl); return _Result; } template -[[nodiscard]] string to_string(const basic_stacktrace<_Al>& _St) { +_NODISCARD string to_string(const basic_stacktrace<_Al>& _St) { string _Result; __std_stacktrace_to_string(_St._Data(), _St.size(), &_Result, _Stacktrace_string_fill_impl); return _Result; @@ -325,14 +325,14 @@ namespace pmr { template <> struct hash { - [[nodiscard]] size_t operator()(const stacktrace_entry& _Val) const noexcept { + _NODISCARD size_t operator()(const stacktrace_entry& _Val) const noexcept { return _Hash_representation(_Val.native_handle()); } }; template struct hash> { - [[nodiscard]] size_t operator()(const basic_stacktrace<_Al>& _Val) const noexcept { + _NODISCARD size_t operator()(const basic_stacktrace<_Al>& _Val) const noexcept { return _Val._Get_hash(); } }; From f0e447c24d2eeecf3c101c24d0054c9afa68f2b1 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 30 Mar 2022 22:21:31 +0300 Subject: [PATCH 086/131] Some review comments --- stl/inc/stacktrace | 48 ++++++++----------- stl/src/stacktrace.cpp | 31 ++++++------ .../tests/GH_000545_include_compare/test.cpp | 1 + .../test_stacktrace.cpp | 10 ++++ tests/std/tests/P0881R7_stacktrace/test.cpp | 40 ++++++++-------- .../test.cpp | 4 ++ 6 files changed, 73 insertions(+), 61 deletions(-) create mode 100644 tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index c66af4696c..3ee08dddd0 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -31,8 +31,8 @@ using _Stacktrace_string_fill = size_t(__stdcall*)( size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback); _EXTERN_C -unsigned short __stdcall __std_stacktrace_capture(unsigned long _Frames_to_skip, unsigned long _Frames_to_capture, - void** _Back_trace, unsigned long* _Back_trace_hash) noexcept; +_NODISCARD unsigned short __stdcall __std_stacktrace_capture(unsigned long _Frames_to_skip, + unsigned long _Frames_to_capture, void** _Back_trace, unsigned long* _Back_trace_hash) noexcept; // Some of these functions may throw // (they would propagate bad_alloc potentially thrown from string::resize_and_overwrite) @@ -60,16 +60,10 @@ _STD_BEGIN inline size_t __stdcall _Stacktrace_string_fill_impl( const size_t _Size, void* const _String, void* const _Context, const _Stacktrace_string_fill_callback _Callback) { if (_Callback) { - struct _Stacktrace_string_fill_op { - size_t operator()(char* _Data, size_t _Size) { + static_cast(_String)->resize_and_overwrite( + _Size, [_Callback, _Context](char* _Data, size_t _Size) noexcept -> size_t { return _Callback(_Data, _Size, _Context); - } - - _Stacktrace_string_fill_callback _Callback; - void* _Context; - }; - - static_cast(_String)->resize_and_overwrite(_Size, _Stacktrace_string_fill_op{_Callback, _Context}); + }); return static_cast(_String)->size(); } else { return static_cast(_String)->capacity(); @@ -106,7 +100,7 @@ public: return _Result; } - _NODISCARD uint_least32_t source_line() const { + _NODISCARD uint_least32_t source_line() const noexcept /* strengthened */ { return __std_stacktrace_source_line(_Address); } @@ -119,10 +113,10 @@ private: void* _Address = nullptr; }; -template +template class basic_stacktrace { private: - using _Frames_t = vector; + using _Frames_t = vector; public: using value_type = stacktrace_entry; @@ -134,7 +128,7 @@ public: using const_reverse_iterator = _STD reverse_iterator; using difference_type = ptrdiff_t; using size_type = size_t; - using allocator_type = _Al; + using allocator_type = _Alloc; // __declspec(noinline) to make the same behavior for debug and release. // We force the current function to be always noinline and add its frame to skipped. @@ -236,12 +230,12 @@ public: } template - _NODISCARD friend bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { - return _Lhs._Hash == _Rhs._Hash && _Lhs._Frames == _Rhs._Frames; + _NODISCARD_FRIEND bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { + return _Lhs._Hash == _Rhs._Hash && _STD equal(_Lhs.begin(), _Lhs.end(), _Rhs.begin(), _Rhs.end()); } template - _NODISCARD friend strong_ordering operator<=>( + _NODISCARD_FRIEND strong_ordering operator<=>( const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { const auto _Result = _Lhs._Frames.size() <=> _Rhs._Frames.size(); if (_Result != strong_ordering::equal) { @@ -253,7 +247,7 @@ public: #else // ^^^ __cpp_lib_concepts ^^^ / vvv !__cpp_lib_concepts vvv for (size_t _Ix = 0, _Mx = _Lhs._Frames.size(); _Ix != _Mx; ++_Ix) { if (_Lhs._Frames[_Ix] != _Rhs._Frames[_Ix]) { - return _Lhs._Frames[_Ix] <=> _Lhs._Frames[_Ix]; + return _Lhs._Frames[_Ix] <=> _Rhs._Frames[_Ix]; } } @@ -278,8 +272,8 @@ public: private: static constexpr size_t _Max_frames = 0xFFFF; - static constexpr bool _Noex_move = allocator_traits<_Al>::propagate_on_container_move_assignment::value - || allocator_traits<_Al>::is_always_equal::value; + static constexpr bool _Noex_move = allocator_traits<_Alloc>::propagate_on_container_move_assignment::value + || allocator_traits<_Alloc>::is_always_equal::value; struct _Internal_t {}; @@ -309,14 +303,14 @@ _NODISCARD string to_string(const basic_stacktrace<_Al>& _St) { return _Result; } -template -basic_ostream& operator<<(basic_ostream& _Os, const stacktrace_entry& _Fx) { - return _Os << to_string(_Fx); +template +basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const stacktrace_entry& _St) { + return _Os << _STD to_string(_St); } -template -basic_ostream& operator<<(basic_ostream& _Os, const basic_stacktrace<_Al>& _Fx) { - return _Os << to_string(_Fx); +template +basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const basic_stacktrace<_Al>& _St) { + return _Os << _STD to_string(_St); } namespace pmr { diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 7cbc04650a..982a4fbeb6 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -18,12 +18,12 @@ #pragma comment(lib, "DbgEng.lib") #pragma comment(lib, "Shlwapi.lib") -// The below function pointer types be in sync with +// The below function pointer types must be in sync with -using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char*, size_t, void* _Context); +using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context); using _Stacktrace_string_fill = size_t(__stdcall*)( - size_t, void* _Str, void* _Context, _Stacktrace_string_fill_callback); + size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback); namespace { template @@ -61,11 +61,11 @@ namespace { void uninitialize() { srw_lock_guard lock{srw}; - // "Phoenix singleton" - destroy and set to null, so that can initialize later again + // "Phoenix singleton" - destroy and set to null, so that it can be initialized later again if (debug_client != nullptr) { if (attached) { - debug_client->DetachProcesses(); + (void) debug_client->DetachProcesses(); attached = false; } @@ -98,11 +98,11 @@ namespace { attached = SUCCEEDED(debug_client->AttachProcess( 0, GetCurrentProcessId(), DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); if (attached) { - debug_control->WaitForEvent(0, INFINITE); + (void) debug_control->WaitForEvent(0, INFINITE); } - // If this failes, will use IDebugSymbols - debug_symbols->QueryInterface(IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); + // If this fails, will use IDebugSymbols + (void) debug_symbols->QueryInterface(IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); // clang-format off constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ | @@ -124,8 +124,8 @@ namespace { 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; // clang-format on - debug_symbols->AddSymbolOptions(add_options); - debug_symbols->RemoveSymbolOptions(remove_options); + (void) debug_symbols->AddSymbolOptions(add_options); + (void) debug_symbols->RemoveSymbolOptions(remove_options); } } @@ -140,7 +140,7 @@ namespace { } size_t get_description(const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { - // Initially pass the current capacity, will retry with bigger buffer if fails. + // Initially pass the current capacity, will retry with bigger buffer if it fails. size_t size = fill(0, str, nullptr, nullptr) - off; HRESULT hr = E_UNEXPECTED; ULONG64 displacement = 0; @@ -211,7 +211,7 @@ namespace { return off; } - [[nodiscard]] unsigned source_line(const void* const address) { + [[nodiscard]] unsigned int source_line(const void* const address) { ULONG line = 0; if (FAILED(debug_symbols->GetLineByOffset( @@ -245,12 +245,13 @@ _EXTERN_C [[nodiscard]] unsigned short __stdcall __std_stacktrace_capture(unsigned long _Frames_to_skip, const unsigned long _Frames_to_capture, void** const _Back_trace, unsigned long* const _Back_trace_hash) noexcept { #ifdef _DEBUG - _Frames_to_skip += 1; // compensate absense of tail call optimization here + _Frames_to_skip += 1; // compensate for absence of tail call optimization here #endif return CaptureStackBackTrace(_Frames_to_skip, _Frames_to_capture, _Back_trace, _Back_trace_hash); } -// Some of these exports may throw (They would propagate bad_alloc potentially thrown from string::resize_and_overwrite) +// Some of these functions may throw (They would propagate bad_alloc potentially thrown from +// string::resize_and_overwrite) void __stdcall __std_stacktrace_description( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { @@ -315,7 +316,7 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si }); } - constexpr size_t max_entry_num = std::size("65536> ") - 1; // maximum possible line number + constexpr size_t max_entry_num = std::size("65536> ") - 1; // maximum possible entry number off = string_fill(_Fill, off + max_entry_num, _Str, [off, i](char* s, size_t) { return std::format_to_n(s + off, max_entry_num, "{}> ", i).out - s; }); diff --git a/tests/std/tests/GH_000545_include_compare/test.cpp b/tests/std/tests/GH_000545_include_compare/test.cpp index 82732c5947..e86ecf03c1 100644 --- a/tests/std/tests/GH_000545_include_compare/test.cpp +++ b/tests/std/tests/GH_000545_include_compare/test.cpp @@ -17,6 +17,7 @@ void test_ranges(); void test_regex(); void test_set(); void test_stack(); +void test_stacktrace(); void test_string(); void test_string_view(); void test_system_error(); diff --git a/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp b/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp new file mode 100644 index 0000000000..aa834cf8a0 --- /dev/null +++ b/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +// Testing LWG-3330 "Include from most library headers" by intentionally NOT including + +static_assert(std::is_eq(std::partial_ordering::equivalent)); + +void test_stacktrace() {} diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index aab02dbd7f..c27cbcce83 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -3,9 +3,12 @@ #include #include +#include #include #include +#include #include +#include #include #ifdef HAS_EXPORT @@ -76,46 +79,46 @@ string trim_past_plus(string str) { } string to_string_using_low_level_members(const stacktrace& st) { - stringstream ss; + ostringstream oss; int n = 0; for (const auto& i : st) { - ss << n << "> "; + oss << n << "> "; ++n; auto l = i.source_line(); if (l != 0) { - ss << i.source_file() << "(" << l << "): "; + oss << i.source_file() << "(" << l << "): "; } - ss << i.description() << "\n"; + oss << i.description() << "\n"; } - return ss.str(); + return oss.str(); } string to_string_using_stream_entry(const stacktrace& st) { - stringstream ss; + ostringstream oss; int n = 0; for (const auto& i : st) { - ss << n << "> "; + oss << n << "> "; ++n; - ss << i << "\n"; + oss << i << "\n"; } - return ss.str(); + return oss.str(); } string to_string_using_to_string_entry(const stacktrace& st) { - stringstream ss; + ostringstream oss; int n = 0; for (const auto& i : st) { - ss << n << "> "; + oss << n << "> "; ++n; - ss << to_string(i) << "\n"; + oss << to_string(i) << "\n"; } - return ss.str(); + return oss.str(); } string to_string_using_stream(const stacktrace& st) { - stringstream ss; - ss << st << "\n"; - return ss.str(); + stringstream oss; + oss << st << "\n"; + return oss.str(); } string to_string_using_to_string(const stacktrace& st) { @@ -229,7 +232,7 @@ void test_impl() { try { (void) all.at(all.size()); assert(false); // should have thrown - } catch (out_of_range) { + } catch (const out_of_range&) { } auto all_copy = all; @@ -272,7 +275,6 @@ void test_impl() { } int main() { - std::thread t{test_impl}; + jthread t{test_impl}; test_impl(); - t.join(); } diff --git a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp index 47047b8d6b..b8d047ef9a 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp +++ b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp @@ -763,14 +763,18 @@ __declspec(dllexport) // for test export main to have it named even { puts("Testing ."); auto desc = stacktrace::current().at(0).description(); + if (auto pos = desc.find("!"); pos != string::npos) { desc = desc.substr(pos + 1); } + if (auto pos = desc.find("+"); pos != string::npos) { desc.resize(pos); } + assert(desc == "main"); } + { puts("Testing ."); bool caught_puppies = false; From c64b9b22b2222b95666f11f80c1a6198af703a16 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 30 Mar 2022 22:23:17 +0300 Subject: [PATCH 087/131] _NODISCARD_FRIEND --- stl/inc/stacktrace | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 3ee08dddd0..fadf84766e 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -104,9 +104,9 @@ public: return __std_stacktrace_source_line(_Address); } - _NODISCARD friend constexpr bool operator==(const stacktrace_entry&, const stacktrace_entry&) noexcept = default; + _NODISCARD_FRIEND constexpr bool operator==(const stacktrace_entry&, const stacktrace_entry&) noexcept = default; - _NODISCARD friend constexpr strong_ordering operator<=>( + _NODISCARD_FRIEND constexpr strong_ordering operator<=>( const stacktrace_entry&, const stacktrace_entry&) noexcept = default; private: From 3a75e2da23177b422286362e0b38d2a25ff23fa3 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 30 Mar 2022 22:24:41 +0300 Subject: [PATCH 088/131] Update tests/std/tests/P0881R7_stacktrace/test.cpp Co-authored-by: Stephan T. Lavavej --- tests/std/tests/P0881R7_stacktrace/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index c27cbcce83..b44c2572db 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -21,7 +21,7 @@ using namespace std; [[maybe_unused]] const int base_line = __LINE__; -// Note: the bellow assumes tail call optimization disabled, which is in case in /Od +// Note: the below assumes that tail call optimization is disabled, which is the case in /Od MAYBE_EXPORT stacktrace all_innermost() { return stacktrace::current(); From f6c962b9ecbc996a25af28c6db3043f6318e4b61 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 30 Mar 2022 22:28:16 +0300 Subject: [PATCH 089/131] --- tests/std/tests/P0881R7_stacktrace/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P0881R7_stacktrace/test.cpp b/tests/std/tests/P0881R7_stacktrace/test.cpp index b44c2572db..74e67bf330 100644 --- a/tests/std/tests/P0881R7_stacktrace/test.cpp +++ b/tests/std/tests/P0881R7_stacktrace/test.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include #include #include From 84ff6cb30ca8ad1ced264048b6eb126d07abf572 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 30 Mar 2022 22:53:59 +0300 Subject: [PATCH 090/131] allocator template parameter --- stl/inc/stacktrace | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index fadf84766e..83c54afaee 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -134,39 +134,39 @@ public: // We force the current function to be always noinline and add its frame to skipped. _NODISCARD __declspec(noinline) static basic_stacktrace - current(const allocator_type& _Alloc = allocator_type()) noexcept { - basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Alloc); + current(const allocator_type& _Al = allocator_type()) noexcept { + basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); _Result._Frames.resize(__std_stacktrace_capture(1, static_cast(_Max_frames), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; } _NODISCARD __declspec(noinline) static basic_stacktrace - current(size_type _Skip, const allocator_type& _Alloc = allocator_type()) noexcept { - basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Alloc); + current(size_type _Skip, const allocator_type& _Al = allocator_type()) noexcept { + basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), static_cast(_Max_frames), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; } _NODISCARD __declspec(noinline) static basic_stacktrace - current(size_type _Skip, size_type _Max_depth, const allocator_type& _Alloc = allocator_type()) noexcept { - basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Alloc); + current(size_type _Skip, size_type _Max_depth, const allocator_type& _Al = allocator_type()) noexcept { + basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Al); _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), static_cast(_Max_depth), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; } basic_stacktrace() noexcept(is_nothrow_default_constructible_v) = default; - explicit basic_stacktrace(const allocator_type& _Alloc) noexcept : _Frames(_Alloc) {} + explicit basic_stacktrace(const allocator_type& _Al) noexcept : _Frames(_Al) {} basic_stacktrace(const basic_stacktrace&) = default; basic_stacktrace(basic_stacktrace&&) noexcept = default; - basic_stacktrace(const basic_stacktrace& _Other, const allocator_type& _Alloc) - : _Frames(_Other._Frames, _Alloc), _Hash(_Other._Hash) {} + basic_stacktrace(const basic_stacktrace& _Other, const allocator_type& _Al) + : _Frames(_Other._Frames, _Al), _Hash(_Other._Hash) {} - basic_stacktrace(basic_stacktrace&& _Other, const allocator_type& _Alloc) - : _Frames(_STD move(_Other._Frames), _Alloc), _Hash(_Other._Hash) {} + basic_stacktrace(basic_stacktrace&& _Other, const allocator_type& _Al) + : _Frames(_STD move(_Other._Frames), _Al), _Hash(_Other._Hash) {} basic_stacktrace& operator=(const basic_stacktrace&) = default; basic_stacktrace& operator=(basic_stacktrace&&) noexcept(_Noex_move) = default; @@ -255,8 +255,8 @@ public: #endif // ^^^ !__cpp_lib_concepts ^^^ } - void swap(basic_stacktrace& _Other) noexcept( - allocator_traits<_Al>::propagate_on_container_swap::value || allocator_traits<_Al>::is_always_equal::value) { + void swap(basic_stacktrace& _Other) noexcept(allocator_traits<_Alloc>::propagate_on_container_swap::value + || allocator_traits<_Alloc>::is_always_equal::value) { _STD swap(_Frames, _Other._Frames); _STD swap(_Hash, _Other._Hash); } @@ -277,7 +277,7 @@ private: struct _Internal_t {}; - basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Alloc) : _Frames(_Max_depth, _Alloc) {} + basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} _Frames_t _Frames; unsigned long _Hash = 0; From cad720849219de2009b6d6440719195f09c76e8d Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 30 Mar 2022 23:17:20 +0300 Subject: [PATCH 091/131] latest --- tests/std/tests/GH_000545_include_compare/env.lst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/GH_000545_include_compare/env.lst b/tests/std/tests/GH_000545_include_compare/env.lst index 351a8293d9..642f530ffa 100644 --- a/tests/std/tests/GH_000545_include_compare/env.lst +++ b/tests/std/tests/GH_000545_include_compare/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\usual_20_matrix.lst +RUNALL_INCLUDE ..\usual_latest_matrix.lst From f4534c6271fee6707985df48a09a96e1ca255ca6 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 30 Mar 2022 23:24:42 +0300 Subject: [PATCH 092/131] comditional stacktrace --- tests/std/tests/GH_000545_include_compare/env.lst | 2 +- tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/GH_000545_include_compare/env.lst b/tests/std/tests/GH_000545_include_compare/env.lst index 642f530ffa..351a8293d9 100644 --- a/tests/std/tests/GH_000545_include_compare/env.lst +++ b/tests/std/tests/GH_000545_include_compare/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\usual_latest_matrix.lst +RUNALL_INCLUDE ..\usual_20_matrix.lst diff --git a/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp b/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp index aa834cf8a0..ddfd6677f8 100644 --- a/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp +++ b/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp @@ -1,10 +1,14 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#ifdef __cpp_lib_stacktrace + #include // Testing LWG-3330 "Include from most library headers" by intentionally NOT including static_assert(std::is_eq(std::partial_ordering::equivalent)); +#endif + void test_stacktrace() {} From 5190527b3dd6a5c18fc26809567a5352e4a5f8c7 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 1 Apr 2022 17:17:15 +0300 Subject: [PATCH 093/131] snprintf --- stl/src/stacktrace.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 982a4fbeb6..fbd6a76f2e 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -6,7 +6,6 @@ // Do not include or define anything else here. // In particular, basic_string must not be included here. -#include #include // clang-format off @@ -170,7 +169,9 @@ namespace { constexpr size_t max_disp_num = std::size("+0x1111222233334444") - 1; // maximum possible offset off = string_fill(fill, off + max_disp_num, str, [displacement, off](char* s, size_t) { - return std::format_to_n(s + off, max_disp_num, "+{:#x}", displacement).out - s; + int ret = std::snprintf(s + off, max_disp_num, "+0x%llX", displacement); + _STL_VERIFY(ret > 0, "formatting error"); + return off + ret; }); } @@ -232,7 +233,9 @@ namespace { constexpr size_t max_line_num = std::size("(4294967295): ") - 1; // maximum possible line number off = string_fill(fill, off + max_line_num, str, [line, off](char* s, size_t) { - return std::format_to_n(s + off, max_line_num, "({}): ", line).out - s; + int ret = std::snprintf(s + off, max_line_num, "(%u): ", line); + _STL_VERIFY(ret > 0, "formatting error"); + return off + ret; }); } @@ -318,8 +321,11 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si constexpr size_t max_entry_num = std::size("65536> ") - 1; // maximum possible entry number - off = string_fill(_Fill, off + max_entry_num, _Str, - [off, i](char* s, size_t) { return std::format_to_n(s + off, max_entry_num, "{}> ", i).out - s; }); + off = string_fill(_Fill, off + max_entry_num, _Str, [off, i](char* s, size_t) { + int ret = std::snprintf(s + off, max_entry_num, "%u> ", static_cast(i)); + _STL_VERIFY(ret > 0, "formatting error"); + return off + ret; + }); off = address_to_string(data[i], _Str, off, _Fill); } From 11f38e1312050d091d8fb12d4f3a87c821c52ff3 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 1 Apr 2022 17:19:27 +0300 Subject: [PATCH 094/131] | --- stl/src/stacktrace.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index fbd6a76f2e..8735014341 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -104,23 +104,23 @@ namespace { (void) debug_symbols->QueryInterface(IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); // clang-format off - constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ | - 0x2 /* SYMOPT_UNDNAME */ | - 0x4 /* SYMOPT_DEFERRED_LOADS */ | - 0x10 /* SYMOPT_LOAD_LINES */ | - 0x20 /* SYMOPT_OMAP_FIND_NEAREST */ | - 0x100 /* SYMOPT_FAIL_CRITICAL_ERRORS */ | - 0x10000 /* SYMOPT_AUTO_PUBLICS */ | - 0x80000 /* SYMOPT_NO_PROMPTS */; - - constexpr ULONG remove_options = 0x8 /* SYMOPT_NO_CPP */ | - 0x40 /* SYMOPT_LOAD_ANYTHING */ | - 0x100 /* SYMOPT_NO_UNQUALIFIED_LOADS */ | - 0x400 /* SYMOPT_EXACT_SYMBOLS */ | - 0x1000 /* SYMOPT_IGNORE_NT_SYMPATH */ | - 0x4000 /* SYMOPT_PUBLICS_ONLY */ | - 0x8000 /* SYMOPT_NO_PUBLICS */ | - 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; + constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ + | 0x2 /* SYMOPT_UNDNAME */ + | 0x4 /* SYMOPT_DEFERRED_LOADS */ + | 0x10 /* SYMOPT_LOAD_LINES */ + | 0x20 /* SYMOPT_OMAP_FIND_NEAREST */ + | 0x100 /* SYMOPT_FAIL_CRITICAL_ERRORS */ + | 0x10000 /* SYMOPT_AUTO_PUBLICS */ + | 0x80000 /* SYMOPT_NO_PROMPTS */; + + constexpr ULONG remove_options = 0x8 /* SYMOPT_NO_CPP */ + | 0x40 /* SYMOPT_LOAD_ANYTHING */ + | 0x100 /* SYMOPT_NO_UNQUALIFIED_LOADS */ + | 0x400 /* SYMOPT_EXACT_SYMBOLS */ + | 0x1000 /* SYMOPT_IGNORE_NT_SYMPATH */ + | 0x4000 /* SYMOPT_PUBLICS_ONLY */ + | 0x8000 /* SYMOPT_NO_PUBLICS */ + | 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; // clang-format on (void) debug_symbols->AddSymbolOptions(add_options); From f793734fcf748892a18761cbc21fb5d1ff521dbe Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 21 Apr 2022 19:07:55 -0700 Subject: [PATCH 095/131] Code review feedback. --- stl/CMakeLists.txt | 6 +- stl/inc/stacktrace | 56 ++++++++++--------- stl/src/stacktrace.cpp | 35 ++++++------ .../tests/GH_000545_include_compare/test.cpp | 1 + .../test_stacktrace.cpp | 3 +- 5 files changed, 55 insertions(+), 46 deletions(-) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index a6ed7ff05d..566ef0243f 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -460,7 +460,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_eha_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHa") add_library(msvcp${D_SUFFIX} SHARED) - target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects msvcp${D_SUFFIX}_init_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "ole32.lib" "DbgEng.lib" "Shlwapi.lib") + target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects msvcp${D_SUFFIX}_init_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "ole32.lib") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_base${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -481,7 +481,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp_1${D_SUFFIX}_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp_1${D_SUFFIX} SHARED) - target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib" "Shlwapi.lib") + target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -528,7 +528,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp${D_SUFFIX}_codecvt_ids SHARED) - target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib" "Shlwapi.lib") + target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_codecvt_ids${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_codecvt_ids${VCLIBS_SUFFIX}") diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 83c54afaee..90497060b5 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -37,33 +37,29 @@ _NODISCARD unsigned short __stdcall __std_stacktrace_capture(unsigned long _Fram // Some of these functions may throw // (they would propagate bad_alloc potentially thrown from string::resize_and_overwrite) -// clang-format off void __stdcall __std_stacktrace_address_to_string( const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); -void __stdcall __std_stacktrace_description( +void __stdcall __std_stacktrace_description( // const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); -void __stdcall __std_stacktrace_source_file( +void __stdcall __std_stacktrace_source_file( // const void* _Address, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); _NODISCARD unsigned int __stdcall __std_stacktrace_source_line(const void* _Address) noexcept; -void __stdcall __std_stacktrace_to_string(const void* _Addresses, size_t _Size, void* _Str, - _Stacktrace_string_fill) noexcept(false); +void __stdcall __std_stacktrace_to_string( + const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); _NODISCARD void* __stdcall __std_stacktrace_get_debug_interface() noexcept; -// clang-format on _END_EXTERN_C _STD_BEGIN inline size_t __stdcall _Stacktrace_string_fill_impl( const size_t _Size, void* const _String, void* const _Context, const _Stacktrace_string_fill_callback _Callback) { if (_Callback) { - static_cast(_String)->resize_and_overwrite( - _Size, [_Callback, _Context](char* _Data, size_t _Size) noexcept -> size_t { - return _Callback(_Data, _Size, _Context); - }); + static_cast(_String)->resize_and_overwrite(_Size, + [_Callback, _Context](char* _Data, size_t _Size) noexcept { return _Callback(_Data, _Size, _Context); }); return static_cast(_String)->size(); } else { return static_cast(_String)->capacity(); @@ -126,8 +122,8 @@ public: using iterator = const_iterator; using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; - using difference_type = ptrdiff_t; - using size_type = size_t; + using difference_type = typename _Frames_t::difference_type; + using size_type = typename _Frames_t::size_type; using allocator_type = _Alloc; // __declspec(noinline) to make the same behavior for debug and release. @@ -243,7 +239,7 @@ public: } #ifdef __cpp_lib_concepts - return _Lhs._Frames <=> _Rhs._Frames; + return _STD lexicographical_compare_three_way(_Lhs.begin(), _Lhs.end(), _Rhs.begin(), _Rhs.end()); #else // ^^^ __cpp_lib_concepts ^^^ / vvv !__cpp_lib_concepts vvv for (size_t _Ix = 0, _Mx = _Lhs._Frames.size(); _Ix != _Mx; ++_Ix) { if (_Lhs._Frames[_Ix] != _Rhs._Frames[_Ix]) { @@ -257,7 +253,7 @@ public: void swap(basic_stacktrace& _Other) noexcept(allocator_traits<_Alloc>::propagate_on_container_swap::value || allocator_traits<_Alloc>::is_always_equal::value) { - _STD swap(_Frames, _Other._Frames); + _Frames.swap(_Other._Frames); _STD swap(_Hash, _Other._Hash); } @@ -275,7 +271,9 @@ private: static constexpr bool _Noex_move = allocator_traits<_Alloc>::propagate_on_container_move_assignment::value || allocator_traits<_Alloc>::is_always_equal::value; - struct _Internal_t {}; + struct _Internal_t { + explicit _Internal_t() = default; + }; basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} @@ -285,8 +283,8 @@ private: using stacktrace = basic_stacktrace>; -template -void swap(basic_stacktrace<_Al>& _Ax, basic_stacktrace<_Al>& _Bx) noexcept(noexcept(_Ax.swap(_Bx))) { +template +void swap(basic_stacktrace<_Alloc>& _Ax, basic_stacktrace<_Alloc>& _Bx) noexcept(noexcept(_Ax.swap(_Bx))) { _Ax.swap(_Bx); } @@ -296,20 +294,20 @@ _NODISCARD inline string to_string(const stacktrace_entry& _Fx) { return _Result; } -template -_NODISCARD string to_string(const basic_stacktrace<_Al>& _St) { +template +_NODISCARD string to_string(const basic_stacktrace<_Alloc>& _St) { string _Result; __std_stacktrace_to_string(_St._Data(), _St.size(), &_Result, _Stacktrace_string_fill_impl); return _Result; } template -basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const stacktrace_entry& _St) { - return _Os << _STD to_string(_St); +basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const stacktrace_entry& _Fx) { + return _Os << _STD to_string(_Fx); } -template -basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const basic_stacktrace<_Al>& _St) { +template +basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const basic_stacktrace<_Alloc>& _St) { return _Os << _STD to_string(_St); } @@ -319,14 +317,20 @@ namespace pmr { template <> struct hash { + _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef stacktrace_entry _ARGUMENT_TYPE_NAME; + _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; + _NODISCARD size_t operator()(const stacktrace_entry& _Val) const noexcept { return _Hash_representation(_Val.native_handle()); } }; -template -struct hash> { - _NODISCARD size_t operator()(const basic_stacktrace<_Al>& _Val) const noexcept { +template +struct hash> { + _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef basic_stacktrace<_Alloc> _ARGUMENT_TYPE_NAME; + _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; + + _NODISCARD size_t operator()(const basic_stacktrace<_Alloc>& _Val) const noexcept { return _Val._Get_hash(); } }; diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 8735014341..e03fa9a170 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -6,7 +6,10 @@ // Do not include or define anything else here. // In particular, basic_string must not be included here. -#include +#include + +#include +#include // clang-format off #include // should be before any header that includes @@ -17,14 +20,14 @@ #pragma comment(lib, "DbgEng.lib") #pragma comment(lib, "Shlwapi.lib") -// The below function pointer types must be in sync with +namespace { + // The below function pointer types must be in sync with -using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context); + using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context); -using _Stacktrace_string_fill = size_t(__stdcall*)( - size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback); + using _Stacktrace_string_fill = size_t(__stdcall*)( + size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback); -namespace { template size_t string_fill(const _Stacktrace_string_fill callback, const size_t size, void* const str, F f) { return callback(size, str, &f, @@ -128,7 +131,7 @@ namespace { } } - if (atexit(uninitialize) != 0) { + if (std::atexit(uninitialize) != 0) { uninitialize(); return false; } @@ -147,7 +150,7 @@ namespace { for (;;) { ULONG new_size = 0; - size_t new_off = string_fill( + const size_t new_off = string_fill( fill, off + size, str, [address, off, size, &new_size, &hr, &displacement](char* s, size_t) { hr = debug_symbols->GetNameByOffset(reinterpret_cast(address), s + off, static_cast(size + 1), &new_size, &displacement); @@ -166,10 +169,10 @@ namespace { } if (displacement != 0) { - constexpr size_t max_disp_num = std::size("+0x1111222233334444") - 1; // maximum possible offset + constexpr size_t max_disp_num = sizeof("+0x1111222233334444") - 1; // maximum possible offset off = string_fill(fill, off + max_disp_num, str, [displacement, off](char* s, size_t) { - int ret = std::snprintf(s + off, max_disp_num, "+0x%llX", displacement); + const int ret = std::snprintf(s + off, max_disp_num, "+0x%llX", displacement); _STL_VERIFY(ret > 0, "formatting error"); return off + ret; }); @@ -187,7 +190,7 @@ namespace { for (;;) { ULONG new_size = 0; - size_t new_off = + const size_t new_off = string_fill(fill, off + size, str, [address, off, size, line, &new_size, &hr](char* s, size_t) { hr = debug_symbols->GetLineByOffset(reinterpret_cast(address), line, s + off, static_cast(size + 1), &new_size, nullptr); @@ -230,10 +233,10 @@ namespace { off = source_file(address, str, off, &line, fill); if (line != 0) { - constexpr size_t max_line_num = std::size("(4294967295): ") - 1; // maximum possible line number + constexpr size_t max_line_num = sizeof("(4294967295): ") - 1; // maximum possible line number off = string_fill(fill, off + max_line_num, str, [line, off](char* s, size_t) { - int ret = std::snprintf(s + off, max_line_num, "(%u): ", line); + const int ret = std::snprintf(s + off, max_line_num, "(%u): ", line); _STL_VERIFY(ret > 0, "formatting error"); return off + ret; }); @@ -278,7 +281,7 @@ void __stdcall __std_stacktrace_source_file( source_file(_Address, _Str, 0, nullptr, _Fill); } -unsigned int __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { +[[nodiscard]] unsigned int __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { const srw_lock_guard lock{srw}; if (!try_initialize()) { @@ -319,10 +322,10 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si }); } - constexpr size_t max_entry_num = std::size("65536> ") - 1; // maximum possible entry number + constexpr size_t max_entry_num = sizeof("65536> ") - 1; // maximum possible entry number off = string_fill(_Fill, off + max_entry_num, _Str, [off, i](char* s, size_t) { - int ret = std::snprintf(s + off, max_entry_num, "%u> ", static_cast(i)); + const int ret = std::snprintf(s + off, max_entry_num, "%u> ", static_cast(i)); _STL_VERIFY(ret > 0, "formatting error"); return off + ret; }); diff --git a/tests/std/tests/GH_000545_include_compare/test.cpp b/tests/std/tests/GH_000545_include_compare/test.cpp index e86ecf03c1..9bba56a931 100644 --- a/tests/std/tests/GH_000545_include_compare/test.cpp +++ b/tests/std/tests/GH_000545_include_compare/test.cpp @@ -47,6 +47,7 @@ int main() { test_regex(); test_set(); test_stack(); + test_stacktrace(); test_string(); test_string_view(); test_system_error(); diff --git a/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp b/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp index ddfd6677f8..3439aa43c4 100644 --- a/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp +++ b/tests/std/tests/GH_000545_include_compare/test_stacktrace.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #ifdef __cpp_lib_stacktrace #include @@ -9,6 +10,6 @@ static_assert(std::is_eq(std::partial_ordering::equivalent)); -#endif +#endif // __cpp_lib_stacktrace void test_stacktrace() {} From a52a4fbf8875341ec1604370bcaf55520d32b1a8 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 21 Apr 2022 20:07:05 -0700 Subject: [PATCH 096/131] Oops, remove argument_type and result_type. --- stl/inc/stacktrace | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 90497060b5..19e1b61b1d 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -317,8 +317,7 @@ namespace pmr { template <> struct hash { - _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef stacktrace_entry _ARGUMENT_TYPE_NAME; - _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; + // This is a C++23 feature, so argument_type and result_type are omitted. _NODISCARD size_t operator()(const stacktrace_entry& _Val) const noexcept { return _Hash_representation(_Val.native_handle()); @@ -327,8 +326,7 @@ struct hash { template struct hash> { - _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef basic_stacktrace<_Alloc> _ARGUMENT_TYPE_NAME; - _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; + // This is a C++23 feature, so argument_type and result_type are omitted. _NODISCARD size_t operator()(const basic_stacktrace<_Alloc>& _Val) const noexcept { return _Val._Get_hash(); From 6e9ad954a827c7f940ed63bc94d1b0581c3134b7 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 5 May 2022 18:08:20 +0300 Subject: [PATCH 097/131] catch 'em all --- stl/inc/stacktrace | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 19e1b61b1d..e79a31625b 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -131,26 +131,38 @@ public: _NODISCARD __declspec(noinline) static basic_stacktrace current(const allocator_type& _Al = allocator_type()) noexcept { + _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); _Result._Frames.resize(__std_stacktrace_capture(1, static_cast(_Max_frames), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; + _CATCH_ALL + return basic_stacktrace{}; + _CATCH_END } _NODISCARD __declspec(noinline) static basic_stacktrace current(size_type _Skip, const allocator_type& _Al = allocator_type()) noexcept { + _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), static_cast(_Max_frames), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; + _CATCH_ALL + return basic_stacktrace{}; + _CATCH_END } _NODISCARD __declspec(noinline) static basic_stacktrace current(size_type _Skip, size_type _Max_depth, const allocator_type& _Al = allocator_type()) noexcept { + _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Al); _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), static_cast(_Max_depth), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); return _Result; + _CATCH_ALL + return basic_stacktrace{}; + _CATCH_END } basic_stacktrace() noexcept(is_nothrow_default_constructible_v) = default; From 194ff85343ad598bbeef25a2ed7ce23baf4f4e50 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 27 May 2022 14:34:56 +0300 Subject: [PATCH 098/131] dynamic import --- stl/CMakeLists.txt | 4 +- stl/src/stacktrace.cpp | 87 ++++++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index e84e5ea0aa..019a6e5b96 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -497,7 +497,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_link_libraries(msvcp_2${D_SUFFIX}_objects PRIVATE Boost::math) add_library(msvcp_2${D_SUFFIX} SHARED) - target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "DbgEng.lib" "Shlwapi.lib") + target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -519,7 +519,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO file(GENERATE OUTPUT "${_ATOMIC_WAIT_DEF_NAME}" CONTENT "${_ATOMIC_WAIT_DEF_CONTENTS}") add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${_ATOMIC_WAIT_DEF_NAME}") - target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "DbgEng.lib" "Shlwapi.lib") + target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "${_ATOMIC_WAIT_OUTPUT_NAME}") diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index e03fa9a170..1ae9e80935 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -58,6 +58,7 @@ namespace { IDebugControl* debug_control = nullptr; bool attached = false; bool initialize_attempted = false; + HMODULE dbgeng = nullptr; SRWLOCK srw = SRWLOCK_INIT; void uninitialize() { @@ -85,49 +86,61 @@ namespace { debug_symbols = nullptr; } + if (dbgeng != nullptr) { + FreeLibrary(dbgeng); + dbgeng = nullptr; + } + initialize_attempted = false; } bool try_initialize() { if (!initialize_attempted) { - // Deliberately not calling CoInitialize[Ex] - // DbgEng.h API works fine without it. COM initialization may have undesired interference with user's code - - if (SUCCEEDED(DebugCreate(IID_IDebugClient, reinterpret_cast(&debug_client))) - && SUCCEEDED(debug_client->QueryInterface(IID_IDebugSymbols, reinterpret_cast(&debug_symbols))) - && SUCCEEDED( - debug_client->QueryInterface(IID_IDebugControl, reinterpret_cast(&debug_control)))) { - attached = SUCCEEDED(debug_client->AttachProcess( - 0, GetCurrentProcessId(), DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); - if (attached) { - (void) debug_control->WaitForEvent(0, INFINITE); + dbgeng = LoadLibraryW(L"dbgeng.dll"); + + if (dbgeng != nullptr) { + auto* debug_create = reinterpret_cast(GetProcAddress(dbgeng, "DebugCreate")); + + // Deliberately not calling CoInitialize[Ex]. DbgEng.h API works fine without it. + // COM initialization may have undesired interference with user's code. + if (debug_create != nullptr + && SUCCEEDED(debug_create(IID_IDebugClient, reinterpret_cast(&debug_client))) + && SUCCEEDED( + debug_client->QueryInterface(IID_IDebugSymbols, reinterpret_cast(&debug_symbols))) + && SUCCEEDED( + debug_client->QueryInterface(IID_IDebugControl, reinterpret_cast(&debug_control)))) { + attached = SUCCEEDED(debug_client->AttachProcess( + 0, GetCurrentProcessId(), DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); + if (attached) { + (void) debug_control->WaitForEvent(0, INFINITE); + } + + // If this fails, will use IDebugSymbols + (void) debug_symbols->QueryInterface(IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); + + // clang-format off + constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ + | 0x2 /* SYMOPT_UNDNAME */ + | 0x4 /* SYMOPT_DEFERRED_LOADS */ + | 0x10 /* SYMOPT_LOAD_LINES */ + | 0x20 /* SYMOPT_OMAP_FIND_NEAREST */ + | 0x100 /* SYMOPT_FAIL_CRITICAL_ERRORS */ + | 0x10000 /* SYMOPT_AUTO_PUBLICS */ + | 0x80000 /* SYMOPT_NO_PROMPTS */; + + constexpr ULONG remove_options = 0x8 /* SYMOPT_NO_CPP */ + | 0x40 /* SYMOPT_LOAD_ANYTHING */ + | 0x100 /* SYMOPT_NO_UNQUALIFIED_LOADS */ + | 0x400 /* SYMOPT_EXACT_SYMBOLS */ + | 0x1000 /* SYMOPT_IGNORE_NT_SYMPATH */ + | 0x4000 /* SYMOPT_PUBLICS_ONLY */ + | 0x8000 /* SYMOPT_NO_PUBLICS */ + | 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; + // clang-format on + + (void) debug_symbols->AddSymbolOptions(add_options); + (void) debug_symbols->RemoveSymbolOptions(remove_options); } - - // If this fails, will use IDebugSymbols - (void) debug_symbols->QueryInterface(IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); - - // clang-format off - constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ - | 0x2 /* SYMOPT_UNDNAME */ - | 0x4 /* SYMOPT_DEFERRED_LOADS */ - | 0x10 /* SYMOPT_LOAD_LINES */ - | 0x20 /* SYMOPT_OMAP_FIND_NEAREST */ - | 0x100 /* SYMOPT_FAIL_CRITICAL_ERRORS */ - | 0x10000 /* SYMOPT_AUTO_PUBLICS */ - | 0x80000 /* SYMOPT_NO_PROMPTS */; - - constexpr ULONG remove_options = 0x8 /* SYMOPT_NO_CPP */ - | 0x40 /* SYMOPT_LOAD_ANYTHING */ - | 0x100 /* SYMOPT_NO_UNQUALIFIED_LOADS */ - | 0x400 /* SYMOPT_EXACT_SYMBOLS */ - | 0x1000 /* SYMOPT_IGNORE_NT_SYMPATH */ - | 0x4000 /* SYMOPT_PUBLICS_ONLY */ - | 0x8000 /* SYMOPT_NO_PUBLICS */ - | 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; - // clang-format on - - (void) debug_symbols->AddSymbolOptions(add_options); - (void) debug_symbols->RemoveSymbolOptions(remove_options); } } From 4859f12072f9c789602ffeafecb4688628397251 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 27 May 2022 15:29:37 +0300 Subject: [PATCH 099/131] format --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 1ae9e80935..69c9e90c3b 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -96,7 +96,7 @@ namespace { bool try_initialize() { if (!initialize_attempted) { - dbgeng = LoadLibraryW(L"dbgeng.dll"); + dbgeng = LoadLibraryW(L"dbgeng.dll"); if (dbgeng != nullptr) { auto* debug_create = reinterpret_cast(GetProcAddress(dbgeng, "DebugCreate")); From c2d9ff651ec0a780a6cbab99739b565c88427300 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 27 May 2022 16:35:19 -0700 Subject: [PATCH 100/131] Code review feedback. --- stl/src/stacktrace.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 69c9e90c3b..49ca96ea4d 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -87,7 +87,7 @@ namespace { } if (dbgeng != nullptr) { - FreeLibrary(dbgeng); + (void) FreeLibrary(dbgeng); dbgeng = nullptr; } @@ -96,10 +96,11 @@ namespace { bool try_initialize() { if (!initialize_attempted) { - dbgeng = LoadLibraryW(L"dbgeng.dll"); + dbgeng = LoadLibraryExW(L"dbgeng.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); if (dbgeng != nullptr) { - auto* debug_create = reinterpret_cast(GetProcAddress(dbgeng, "DebugCreate")); + const auto debug_create = + reinterpret_cast(GetProcAddress(dbgeng, "DebugCreate")); // Deliberately not calling CoInitialize[Ex]. DbgEng.h API works fine without it. // COM initialization may have undesired interference with user's code. From 2a5fbdf6aafaf7ca7207d309ad632e4befc259f0 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 10:20:26 +0300 Subject: [PATCH 101/131] explain functional nightmare --- stl/inc/stacktrace | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index e79a31625b..bbee39aaa2 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -25,6 +25,18 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new +// The separately compiled part of implementation calls a function pointer of _Stacktrace_string_fill type +// to allocate a buffer for string output. The called function does the buffer allocation and calls a function pointer +// of _Stacktrace_string_fill_callback type to fill the buffer. This is needed to type-erase or , and +// make it possible to keep the separately compiled implementation in the import library. +// +// Additionally, _Stacktrace_string_fill can be called with nullptr string parameter to determine already reserved +// string buffer for cases when the size is not known before an attempt to fill it -- this potentially avoids both extra +// fill attempt and extra allocation if the reserved size is enough. +// +// Currently, _Stacktrace_string_fill implementation is based on string::resize_and_overwrite, and for ostream it uses +// temporary string, but it could be different, e.g avoid building a complete string and output to stream by portions. + using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context); using _Stacktrace_string_fill = size_t(__stdcall*)( From 414c9426a6c056934cf0f5d34bc29652f374c7e0 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 10:43:12 +0300 Subject: [PATCH 102/131] format --- stl/inc/stacktrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index bbee39aaa2..2af318c329 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -28,7 +28,7 @@ _STL_DISABLE_CLANG_WARNINGS // The separately compiled part of implementation calls a function pointer of _Stacktrace_string_fill type // to allocate a buffer for string output. The called function does the buffer allocation and calls a function pointer // of _Stacktrace_string_fill_callback type to fill the buffer. This is needed to type-erase or , and -// make it possible to keep the separately compiled implementation in the import library. +// make it possible to keep the separately compiled implementation in the import library. // // Additionally, _Stacktrace_string_fill can be called with nullptr string parameter to determine already reserved // string buffer for cases when the size is not known before an attempt to fill it -- this potentially avoids both extra From bf0c312b5d29e876a8425774d7630d0f596ab370 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 11:38:58 +0300 Subject: [PATCH 103/131] skip that actually --- stl/inc/stacktrace | 3 --- 1 file changed, 3 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 2af318c329..1c8ec7cb19 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -33,9 +33,6 @@ _STL_DISABLE_CLANG_WARNINGS // Additionally, _Stacktrace_string_fill can be called with nullptr string parameter to determine already reserved // string buffer for cases when the size is not known before an attempt to fill it -- this potentially avoids both extra // fill attempt and extra allocation if the reserved size is enough. -// -// Currently, _Stacktrace_string_fill implementation is based on string::resize_and_overwrite, and for ostream it uses -// temporary string, but it could be different, e.g avoid building a complete string and output to stream by portions. using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context); From 6f939fd0b41c07982b286a5fc313575827516f9a Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 18:54:42 +0300 Subject: [PATCH 104/131] _nolock --- stl/src/stacktrace.cpp | 57 +++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 49ca96ea4d..e78a91011b 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -61,9 +61,7 @@ namespace { HMODULE dbgeng = nullptr; SRWLOCK srw = SRWLOCK_INIT; - void uninitialize() { - srw_lock_guard lock{srw}; - + void uninitialize_nolock() { // "Phoenix singleton" - destroy and set to null, so that it can be initialized later again if (debug_client != nullptr) { @@ -94,7 +92,13 @@ namespace { initialize_attempted = false; } - bool try_initialize() { + void uninitialize() { + srw_lock_guard lock{srw}; + + uninitialize_nolock(); + } + + bool try_initialize_nolock() { if (!initialize_attempted) { dbgeng = LoadLibraryExW(L"dbgeng.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); @@ -146,7 +150,7 @@ namespace { } if (std::atexit(uninitialize) != 0) { - uninitialize(); + uninitialize_nolock(); return false; } @@ -155,7 +159,8 @@ namespace { return debug_symbols != nullptr; } - size_t get_description(const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { + size_t get_description_nolock( + const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { // Initially pass the current capacity, will retry with bigger buffer if it fails. size_t size = fill(0, str, nullptr, nullptr) - off; HRESULT hr = E_UNEXPECTED; @@ -195,7 +200,7 @@ namespace { return off; } - size_t source_file( + size_t source_file_nolock( const void* const address, void* const str, size_t off, ULONG* const line, const _Stacktrace_string_fill fill) { // Initially pass the current capacity, will retry with bigger buffer if fails. size_t size = fill(0, str, nullptr, nullptr) - off; @@ -229,7 +234,7 @@ namespace { return off; } - [[nodiscard]] unsigned int source_line(const void* const address) { + [[nodiscard]] unsigned int source_line_nolock(const void* const address) { ULONG line = 0; if (FAILED(debug_symbols->GetLineByOffset( @@ -240,11 +245,11 @@ namespace { return line; } - size_t address_to_string( + size_t address_to_string_nolock( const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { ULONG line = 0; - off = source_file(address, str, off, &line, fill); + off = source_file_nolock(address, str, off, &line, fill); if (line != 0) { constexpr size_t max_line_num = sizeof("(4294967295): ") - 1; // maximum possible line number @@ -256,7 +261,7 @@ namespace { }); } - return get_description(address, str, off, fill); + return get_description_nolock(address, str, off, fill); } } // namespace @@ -277,50 +282,50 @@ void __stdcall __std_stacktrace_description( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; - if (!try_initialize()) { + if (!try_initialize_nolock()) { return; } - get_description(_Address, _Str, 0, _Fill); + get_description_nolock(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_source_file( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; - if (!try_initialize()) { + if (!try_initialize_nolock()) { return; } - source_file(_Address, _Str, 0, nullptr, _Fill); + source_file_nolock(_Address, _Str, 0, nullptr, _Fill); } [[nodiscard]] unsigned int __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { const srw_lock_guard lock{srw}; - if (!try_initialize()) { + if (!try_initialize_nolock()) { return 0; } - return source_line(_Address); + return source_line_nolock(_Address); } void __stdcall __std_stacktrace_address_to_string( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; - if (!try_initialize()) { + if (!try_initialize_nolock()) { return; } - address_to_string(_Address, _Str, 0, _Fill); + address_to_string_nolock(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const size_t _Size, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { const srw_lock_guard lock{srw}; - if (!try_initialize()) { + if (!try_initialize_nolock()) { return; } @@ -344,17 +349,7 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si return off + ret; }); - off = address_to_string(data[i], _Str, off, _Fill); + off = address_to_string_nolock(data[i], _Str, off, _Fill); } } - -[[nodiscard]] void* __stdcall __std_stacktrace_get_debug_interface() noexcept { - const srw_lock_guard lock{srw}; - - if (!try_initialize()) { - return nullptr; - } - - return debug_symbols; -} _END_EXTERN_C From 9881073a832f0921253798b4e19e65600220af8c Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 19:17:41 +0300 Subject: [PATCH 105/131] struct --- stl/src/stacktrace.cpp | 349 +++++++++++++++++++++-------------------- 1 file changed, 178 insertions(+), 171 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index e78a91011b..22e16f5074 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -52,78 +52,67 @@ namespace { SRWLOCK* const locked; }; - IDebugClient* debug_client = nullptr; - IDebugSymbols* debug_symbols = nullptr; - IDebugSymbols3* debug_symbols3 = nullptr; - IDebugControl* debug_control = nullptr; - bool attached = false; - bool initialize_attempted = false; - HMODULE dbgeng = nullptr; - SRWLOCK srw = SRWLOCK_INIT; - - void uninitialize_nolock() { - // "Phoenix singleton" - destroy and set to null, so that it can be initialized later again - - if (debug_client != nullptr) { - if (attached) { - (void) debug_client->DetachProcesses(); - attached = false; - } - - debug_client->Release(); - debug_client = nullptr; - } + void lock_and_uninitialize(); - if (debug_control != nullptr) { - debug_control->Release(); - debug_control = nullptr; - } + struct dbg_eng_data { + static void uninitialize() { + // "Phoenix singleton" - destroy and set to null, so that it can be initialized later again - if (debug_symbols != nullptr) { - debug_symbols->Release(); - debug_symbols = nullptr; - } - - if (dbgeng != nullptr) { - (void) FreeLibrary(dbgeng); - dbgeng = nullptr; - } - - initialize_attempted = false; - } + if (debug_client != nullptr) { + if (attached) { + (void) debug_client->DetachProcesses(); + attached = false; + } - void uninitialize() { - srw_lock_guard lock{srw}; + debug_client->Release(); + debug_client = nullptr; + } - uninitialize_nolock(); - } + if (debug_control != nullptr) { + debug_control->Release(); + debug_control = nullptr; + } - bool try_initialize_nolock() { - if (!initialize_attempted) { - dbgeng = LoadLibraryExW(L"dbgeng.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (debug_symbols != nullptr) { + debug_symbols->Release(); + debug_symbols = nullptr; + } if (dbgeng != nullptr) { - const auto debug_create = - reinterpret_cast(GetProcAddress(dbgeng, "DebugCreate")); - - // Deliberately not calling CoInitialize[Ex]. DbgEng.h API works fine without it. - // COM initialization may have undesired interference with user's code. - if (debug_create != nullptr - && SUCCEEDED(debug_create(IID_IDebugClient, reinterpret_cast(&debug_client))) - && SUCCEEDED( - debug_client->QueryInterface(IID_IDebugSymbols, reinterpret_cast(&debug_symbols))) - && SUCCEEDED( - debug_client->QueryInterface(IID_IDebugControl, reinterpret_cast(&debug_control)))) { - attached = SUCCEEDED(debug_client->AttachProcess( - 0, GetCurrentProcessId(), DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); - if (attached) { - (void) debug_control->WaitForEvent(0, INFINITE); - } + (void) FreeLibrary(dbgeng); + dbgeng = nullptr; + } - // If this fails, will use IDebugSymbols - (void) debug_symbols->QueryInterface(IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); + initialize_attempted = false; + } - // clang-format off + static bool try_initialize() { + if (!initialize_attempted) { + dbgeng = LoadLibraryExW(L"dbgeng.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + + if (dbgeng != nullptr) { + const auto debug_create = + reinterpret_cast(GetProcAddress(dbgeng, "DebugCreate")); + + // Deliberately not calling CoInitialize[Ex]. DbgEng.h API works fine without it. + // COM initialization may have undesired interference with user's code. + if (debug_create != nullptr + && SUCCEEDED(debug_create(IID_IDebugClient, reinterpret_cast(&debug_client))) + && SUCCEEDED( + debug_client->QueryInterface(IID_IDebugSymbols, reinterpret_cast(&debug_symbols))) + && SUCCEEDED(debug_client->QueryInterface( + IID_IDebugControl, reinterpret_cast(&debug_control)))) { + attached = SUCCEEDED(debug_client->AttachProcess( + 0, GetCurrentProcessId(), DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); + if (attached) { + (void) debug_control->WaitForEvent(0, INFINITE); + } + + // If this fails, will use IDebugSymbols + (void) debug_symbols->QueryInterface( + IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); + + // clang-format off constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ | 0x2 /* SYMOPT_UNDNAME */ | 0x4 /* SYMOPT_DEFERRED_LOADS */ @@ -141,129 +130,147 @@ namespace { | 0x4000 /* SYMOPT_PUBLICS_ONLY */ | 0x8000 /* SYMOPT_NO_PUBLICS */ | 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; - // clang-format on + // clang-format on - (void) debug_symbols->AddSymbolOptions(add_options); - (void) debug_symbols->RemoveSymbolOptions(remove_options); + (void) debug_symbols->AddSymbolOptions(add_options); + (void) debug_symbols->RemoveSymbolOptions(remove_options); + } } } - } - if (std::atexit(uninitialize) != 0) { - uninitialize_nolock(); - return false; - } - - initialize_attempted = true; + if (std::atexit(lock_and_uninitialize) != 0) { + uninitialize(); + return false; + } - return debug_symbols != nullptr; - } + initialize_attempted = true; - size_t get_description_nolock( - const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { - // Initially pass the current capacity, will retry with bigger buffer if it fails. - size_t size = fill(0, str, nullptr, nullptr) - off; - HRESULT hr = E_UNEXPECTED; - ULONG64 displacement = 0; + return debug_symbols != nullptr; + } - for (;;) { - ULONG new_size = 0; + static size_t get_description( + const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { + // Initially pass the current capacity, will retry with bigger buffer if it fails. + size_t size = fill(0, str, nullptr, nullptr) - off; + HRESULT hr = E_UNEXPECTED; + ULONG64 displacement = 0; + + for (;;) { + ULONG new_size = 0; + + const size_t new_off = string_fill( + fill, off + size, str, [address, off, size, &new_size, &hr, &displacement](char* s, size_t) { + hr = debug_symbols->GetNameByOffset(reinterpret_cast(address), s + off, + static_cast(size + 1), &new_size, &displacement); + + return (hr == S_OK) ? off + new_size - 1 : off; + }); + + if (hr == S_OK) { + off = new_off; + break; + } else if (hr == S_FALSE) { + size = new_size - 1; // retry with bigger buffer + } else { + return off; + } + } - const size_t new_off = string_fill( - fill, off + size, str, [address, off, size, &new_size, &hr, &displacement](char* s, size_t) { - hr = debug_symbols->GetNameByOffset(reinterpret_cast(address), s + off, - static_cast(size + 1), &new_size, &displacement); + if (displacement != 0) { + constexpr size_t max_disp_num = sizeof("+0x1111222233334444") - 1; // maximum possible offset - return (hr == S_OK) ? off + new_size - 1 : off; + off = string_fill(fill, off + max_disp_num, str, [displacement, off](char* s, size_t) { + const int ret = std::snprintf(s + off, max_disp_num, "+0x%llX", displacement); + _STL_VERIFY(ret > 0, "formatting error"); + return off + ret; }); - - if (hr == S_OK) { - off = new_off; - break; - } else if (hr == S_FALSE) { - size = new_size - 1; // retry with bigger buffer - } else { - return off; } - } - if (displacement != 0) { - constexpr size_t max_disp_num = sizeof("+0x1111222233334444") - 1; // maximum possible offset - - off = string_fill(fill, off + max_disp_num, str, [displacement, off](char* s, size_t) { - const int ret = std::snprintf(s + off, max_disp_num, "+0x%llX", displacement); - _STL_VERIFY(ret > 0, "formatting error"); - return off + ret; - }); + return off; } - return off; - } - - size_t source_file_nolock( - const void* const address, void* const str, size_t off, ULONG* const line, const _Stacktrace_string_fill fill) { - // Initially pass the current capacity, will retry with bigger buffer if fails. - size_t size = fill(0, str, nullptr, nullptr) - off; - HRESULT hr = E_UNEXPECTED; - - for (;;) { - ULONG new_size = 0; - - const size_t new_off = - string_fill(fill, off + size, str, [address, off, size, line, &new_size, &hr](char* s, size_t) { - hr = debug_symbols->GetLineByOffset(reinterpret_cast(address), line, s + off, - static_cast(size + 1), &new_size, nullptr); - - return (hr == S_OK) ? off + new_size - 1 : off; - }); + static size_t source_file(const void* const address, void* const str, size_t off, ULONG* const line, + const _Stacktrace_string_fill fill) { + // Initially pass the current capacity, will retry with bigger buffer if fails. + size_t size = fill(0, str, nullptr, nullptr) - off; + HRESULT hr = E_UNEXPECTED; + + for (;;) { + ULONG new_size = 0; + + const size_t new_off = + string_fill(fill, off + size, str, [address, off, size, line, &new_size, &hr](char* s, size_t) { + hr = debug_symbols->GetLineByOffset(reinterpret_cast(address), line, s + off, + static_cast(size + 1), &new_size, nullptr); + + return (hr == S_OK) ? off + new_size - 1 : off; + }); + + if (hr == S_OK) { + off = new_off; + break; + } else if (hr == S_FALSE) { + size = new_size - 1; // retry with bigger buffer + } else { + if (line) { + *line = 0; + } - if (hr == S_OK) { - off = new_off; - break; - } else if (hr == S_FALSE) { - size = new_size - 1; // retry with bigger buffer - } else { - if (line) { - *line = 0; + return off; } - - return off; } + + return off; } - return off; - } + [[nodiscard]] static unsigned int source_line(const void* const address) { + ULONG line = 0; - [[nodiscard]] unsigned int source_line_nolock(const void* const address) { - ULONG line = 0; + if (FAILED(debug_symbols->GetLineByOffset( + reinterpret_cast(address), &line, nullptr, 0, nullptr, nullptr))) { + return 0; + } - if (FAILED(debug_symbols->GetLineByOffset( - reinterpret_cast(address), &line, nullptr, 0, nullptr, nullptr))) { - return 0; + return line; } - return line; - } + static size_t address_to_string( + const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { + ULONG line = 0; - size_t address_to_string_nolock( - const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { - ULONG line = 0; + off = source_file(address, str, off, &line, fill); - off = source_file_nolock(address, str, off, &line, fill); + if (line != 0) { + constexpr size_t max_line_num = sizeof("(4294967295): ") - 1; // maximum possible line number - if (line != 0) { - constexpr size_t max_line_num = sizeof("(4294967295): ") - 1; // maximum possible line number + off = string_fill(fill, off + max_line_num, str, [line, off](char* s, size_t) { + const int ret = std::snprintf(s + off, max_line_num, "(%u): ", line); + _STL_VERIFY(ret > 0, "formatting error"); + return off + ret; + }); + } - off = string_fill(fill, off + max_line_num, str, [line, off](char* s, size_t) { - const int ret = std::snprintf(s + off, max_line_num, "(%u): ", line); - _STL_VERIFY(ret > 0, "formatting error"); - return off + ret; - }); + return get_description(address, str, off, fill); } - return get_description_nolock(address, str, off, fill); - } + public: + inline static SRWLOCK srw; + + private: + inline static IDebugClient* debug_client = nullptr; + inline static IDebugSymbols* debug_symbols = nullptr; + inline static IDebugSymbols3* debug_symbols3 = nullptr; + inline static IDebugControl* debug_control = nullptr; + inline static bool attached = false; + inline static bool initialize_attempted = false; + inline static HMODULE dbgeng = nullptr; + }; + + void lock_and_uninitialize() { + const srw_lock_guard lock{dbg_eng_data::srw}; + dbg_eng_data::uninitialize(); + } } // namespace _EXTERN_C @@ -280,52 +287,52 @@ _EXTERN_C void __stdcall __std_stacktrace_description( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { - const srw_lock_guard lock{srw}; + const srw_lock_guard lock{dbg_eng_data::srw}; - if (!try_initialize_nolock()) { + if (!dbg_eng_data::try_initialize()) { return; } - get_description_nolock(_Address, _Str, 0, _Fill); + dbg_eng_data::get_description(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_source_file( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { - const srw_lock_guard lock{srw}; + const srw_lock_guard lock{dbg_eng_data::srw}; - if (!try_initialize_nolock()) { + if (!dbg_eng_data::try_initialize()) { return; } - source_file_nolock(_Address, _Str, 0, nullptr, _Fill); + dbg_eng_data::source_file(_Address, _Str, 0, nullptr, _Fill); } [[nodiscard]] unsigned int __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { - const srw_lock_guard lock{srw}; + const srw_lock_guard lock{dbg_eng_data::srw}; - if (!try_initialize_nolock()) { + if (!dbg_eng_data::try_initialize()) { return 0; } - return source_line_nolock(_Address); + return dbg_eng_data::source_line(_Address); } void __stdcall __std_stacktrace_address_to_string( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { - const srw_lock_guard lock{srw}; + const srw_lock_guard lock{dbg_eng_data::srw}; - if (!try_initialize_nolock()) { + if (!dbg_eng_data::try_initialize()) { return; } - address_to_string_nolock(_Address, _Str, 0, _Fill); + dbg_eng_data::address_to_string(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const size_t _Size, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { - const srw_lock_guard lock{srw}; + const srw_lock_guard lock{dbg_eng_data::srw}; - if (!try_initialize_nolock()) { + if (!dbg_eng_data::try_initialize()) { return; } @@ -349,7 +356,7 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si return off + ret; }); - off = address_to_string_nolock(data[i], _Str, off, _Fill); + off = dbg_eng_data::address_to_string(data[i], _Str, off, _Fill); } } _END_EXTERN_C From b8551231645ba39da2c2a91f97d85adea77a18a2 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 19:42:02 +0300 Subject: [PATCH 106/131] some review comments --- stl/inc/stacktrace | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 1c8ec7cb19..719f2ebd8e 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -142,8 +142,9 @@ public: current(const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); - _Result._Frames.resize(__std_stacktrace_capture(1, static_cast(_Max_frames), - reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); + const unsigned short _Actual_size = + __std_stacktrace_capture(1, static_cast(_Max_frames), _To_voidptr_array(), &_Result._Hash); + _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL return basic_stacktrace{}; @@ -154,8 +155,9 @@ public: current(size_type _Skip, const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); - _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), - static_cast(_Max_frames), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); + const unsigned short _Actual_size = __std_stacktrace_capture(static_cast(_Skip + 1), + static_cast(_Max_frames), _To_voidptr_array(), &_Result._Hash); + _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL return basic_stacktrace{}; @@ -166,8 +168,8 @@ public: current(size_type _Skip, size_type _Max_depth, const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Al); - _Result._Frames.resize(__std_stacktrace_capture(static_cast(_Skip + 1), - static_cast(_Max_depth), reinterpret_cast(_Result._Frames.data()), &_Result._Hash)); + const unsigned short _Actual_size = __std_stacktrace_capture(static_cast(_Skip + 1), + static_cast(_Max_depth), _To_voidptr_array(), &_Result._Hash); return _Result; _CATCH_ALL return basic_stacktrace{}; @@ -298,6 +300,12 @@ private: basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} + void** _To_voidptr_array() { + _STL_INTERNAL_STATIC_ASSERT(sizeof(void*) == sizeof(*this)); + _STL_INTERNAL_STATIC_ASSERT(alignof(void*) == alignof(*this)); + return reinterpret_cast(_Result._Frames.data()); + } + _Frames_t _Frames; unsigned long _Hash = 0; }; From 7c1d9208bad1fe85eb4ec06f4c6750a5e826ca64 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 19:50:47 +0300 Subject: [PATCH 107/131] -__std_stacktrace_get_debug_interface --- stl/inc/stacktrace | 2 -- 1 file changed, 2 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 719f2ebd8e..6f3bdd762d 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -59,8 +59,6 @@ _NODISCARD unsigned int __stdcall __std_stacktrace_source_line(const void* _Addr void __stdcall __std_stacktrace_to_string( const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); - -_NODISCARD void* __stdcall __std_stacktrace_get_debug_interface() noexcept; _END_EXTERN_C _STD_BEGIN From 62423452363b6508f5dafa655296dfe0f0fcff48 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 20:12:49 +0300 Subject: [PATCH 108/131] fix build --- stl/inc/stacktrace | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 6f3bdd762d..3206035375 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -140,8 +140,8 @@ public: current(const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); - const unsigned short _Actual_size = - __std_stacktrace_capture(1, static_cast(_Max_frames), _To_voidptr_array(), &_Result._Hash); + const unsigned short _Actual_size = __std_stacktrace_capture( + 1, static_cast(_Max_frames), _Result._To_voidptr_array(), &_Result._Hash); _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL @@ -154,7 +154,7 @@ public: _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); const unsigned short _Actual_size = __std_stacktrace_capture(static_cast(_Skip + 1), - static_cast(_Max_frames), _To_voidptr_array(), &_Result._Hash); + static_cast(_Max_frames), _Result._To_voidptr_array(), &_Result._Hash); _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL @@ -167,7 +167,8 @@ public: _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Al); const unsigned short _Actual_size = __std_stacktrace_capture(static_cast(_Skip + 1), - static_cast(_Max_depth), _To_voidptr_array(), &_Result._Hash); + static_cast(_Max_depth), _Result._To_voidptr_array(), &_Result._Hash); + _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL return basic_stacktrace{}; @@ -299,9 +300,7 @@ private: basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} void** _To_voidptr_array() { - _STL_INTERNAL_STATIC_ASSERT(sizeof(void*) == sizeof(*this)); - _STL_INTERNAL_STATIC_ASSERT(alignof(void*) == alignof(*this)); - return reinterpret_cast(_Result._Frames.data()); + return reinterpret_cast(_Frames.data()); } _Frames_t _Frames; From 933be576af02d872e8aebdd75ecc7e74c3645de7 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 1 Jun 2022 20:14:57 +0300 Subject: [PATCH 109/131] _STL_INTERNAL_STATIC_ASSERT --- stl/inc/stacktrace | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 3206035375..f538694ff6 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -300,6 +300,8 @@ private: basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} void** _To_voidptr_array() { + _STL_INTERNAL_STATIC_ASSERT(sizeof(void*) == sizeof(stacktrace_entry)); + _STL_INTERNAL_STATIC_ASSERT(alignof(void*) == alignof(stacktrace_entry)); return reinterpret_cast(_Frames.data()); } From 5d813d685974853ccc9588b47253d8198e406b69 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 2 Jun 2022 11:17:49 +0300 Subject: [PATCH 110/131] more noexcept --- stl/inc/stacktrace | 2 +- stl/src/stacktrace.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index f538694ff6..f054369cfb 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -34,7 +34,7 @@ _STL_DISABLE_CLANG_WARNINGS // string buffer for cases when the size is not known before an attempt to fill it -- this potentially avoids both extra // fill attempt and extra allocation if the reserved size is enough. -using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context); +using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context) _NOEXCEPT_FNPTR; using _Stacktrace_string_fill = size_t(__stdcall*)( size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback); diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 22e16f5074..c5ac38e1cc 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -20,18 +20,18 @@ #pragma comment(lib, "DbgEng.lib") #pragma comment(lib, "Shlwapi.lib") -namespace { - // The below function pointer types must be in sync with +// The below function pointer types must be in sync with - using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context); +using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context) _NOEXCEPT_FNPTR; - using _Stacktrace_string_fill = size_t(__stdcall*)( - size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback); +using _Stacktrace_string_fill = size_t(__stdcall*)( + size_t _Size, void* _String, void* _Context, _Stacktrace_string_fill_callback _Callback); +namespace { template size_t string_fill(const _Stacktrace_string_fill callback, const size_t size, void* const str, F f) { return callback(size, str, &f, - [](char* s, size_t sz, void* context) -> size_t { return (*static_cast(context))(s, sz); }); + [](char* s, size_t sz, void* context) noexcept -> size_t { return (*static_cast(context))(s, sz); }); } // TRANSITION, GH-2285. Use SRWLOCK instead of std::mutex to avoid nontrivial constructor and nontrivial destructor From 0aadf48d489199f7fa23aec32576537b733d76ab Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 2 Jun 2022 11:47:12 +0300 Subject: [PATCH 111/131] Adjust integers --- stl/inc/stacktrace | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index f054369cfb..98d38c93b7 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -150,11 +150,11 @@ public: } _NODISCARD __declspec(noinline) static basic_stacktrace - current(size_type _Skip, const allocator_type& _Al = allocator_type()) noexcept { + current(const size_type _Skip, const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); - const unsigned short _Actual_size = __std_stacktrace_capture(static_cast(_Skip + 1), - static_cast(_Max_frames), _Result._To_voidptr_array(), &_Result._Hash); + const unsigned short _Actual_size = __std_stacktrace_capture( + _Adjust_skip(_Skip), static_cast(_Max_frames), _Result._To_voidptr_array(), &_Result._Hash); _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL @@ -163,11 +163,16 @@ public: } _NODISCARD __declspec(noinline) static basic_stacktrace - current(size_type _Skip, size_type _Max_depth, const allocator_type& _Al = allocator_type()) noexcept { + current(const size_type _Skip, size_type _Max_depth, const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Al); - const unsigned short _Actual_size = __std_stacktrace_capture(static_cast(_Skip + 1), - static_cast(_Max_depth), _Result._To_voidptr_array(), &_Result._Hash); + + if (_Max_depth > _Max_frames) { + _Max_depth = _Max_frames; + } + + const unsigned short _Actual_size = __std_stacktrace_capture( + _Adjust_skip(_Skip), static_cast(_Max_depth), _Result._To_voidptr_array(), &_Result._Hash); _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL @@ -305,6 +310,11 @@ private: return reinterpret_cast(_Frames.data()); } + unsigned long _Adjust_skip(size_t _Skip) { + _Skip += 1; // Skip current frame + return _Skip < ULONG_MAX ? static_cast(_Skip) : ULONG_MAX; + } + _Frames_t _Frames; unsigned long _Hash = 0; }; From 72d9839280a8140214e7b62fbc8fd125c664d727 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 2 Jun 2022 12:18:43 +0300 Subject: [PATCH 112/131] fix build, exception safety --- stl/inc/stacktrace | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 98d38c93b7..d8b133298f 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -139,33 +139,33 @@ public: _NODISCARD __declspec(noinline) static basic_stacktrace current(const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN - basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); + basic_stacktrace _Result{_Internal_t{}, _Max_frames, _Al}; const unsigned short _Actual_size = __std_stacktrace_capture( 1, static_cast(_Max_frames), _Result._To_voidptr_array(), &_Result._Hash); _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL - return basic_stacktrace{}; + return basic_stacktrace{_Internal_t{}, _Al}; _CATCH_END } _NODISCARD __declspec(noinline) static basic_stacktrace current(const size_type _Skip, const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN - basic_stacktrace _Result(_Internal_t{}, _Max_frames, _Al); + basic_stacktrace _Result{_Internal_t{}, _Max_frames, _Al}; const unsigned short _Actual_size = __std_stacktrace_capture( _Adjust_skip(_Skip), static_cast(_Max_frames), _Result._To_voidptr_array(), &_Result._Hash); _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL - return basic_stacktrace{}; + return basic_stacktrace{_Internal_t{}, _Al}; _CATCH_END } _NODISCARD __declspec(noinline) static basic_stacktrace current(const size_type _Skip, size_type _Max_depth, const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN - basic_stacktrace _Result(_Internal_t{}, _Max_depth, _Al); + basic_stacktrace _Result{_Internal_t{}, _Max_depth, _Al}; if (_Max_depth > _Max_frames) { _Max_depth = _Max_frames; @@ -176,7 +176,7 @@ public: _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL - return basic_stacktrace{}; + return basic_stacktrace{_Internal_t{}, _Al}; _CATCH_END } @@ -304,13 +304,15 @@ private: basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} + basic_stacktrace(_Internal_t, const allocator_type& _Al) noexcept : _Frames(_Al) {} + void** _To_voidptr_array() { _STL_INTERNAL_STATIC_ASSERT(sizeof(void*) == sizeof(stacktrace_entry)); _STL_INTERNAL_STATIC_ASSERT(alignof(void*) == alignof(stacktrace_entry)); return reinterpret_cast(_Frames.data()); } - unsigned long _Adjust_skip(size_t _Skip) { + static unsigned long _Adjust_skip(size_t _Skip) { _Skip += 1; // Skip current frame return _Skip < ULONG_MAX ? static_cast(_Skip) : ULONG_MAX; } From 7e543c30aeb45147bd9b058826e0add59d2361bc Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Jun 2022 18:06:04 -0700 Subject: [PATCH 113/131] Drop `#pragma comment`s for DbgEng.lib and Shlwapi.lib. --- stl/src/stacktrace.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index c5ac38e1cc..c6fc573e63 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -17,9 +17,6 @@ #include // clang-format on -#pragma comment(lib, "DbgEng.lib") -#pragma comment(lib, "Shlwapi.lib") - // The below function pointer types must be in sync with using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context) _NOEXCEPT_FNPTR; From 9c5af009e251fb98d465a064241bcd73d6ed68db Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Jun 2022 18:08:28 -0700 Subject: [PATCH 114/131] Mark _To_voidptr_array/_Adjust_skip as _NODISCARD/noexcept. --- stl/inc/stacktrace | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index d8b133298f..bdda2b6b39 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -306,13 +306,13 @@ private: basic_stacktrace(_Internal_t, const allocator_type& _Al) noexcept : _Frames(_Al) {} - void** _To_voidptr_array() { + _NODISCARD void** _To_voidptr_array() noexcept { _STL_INTERNAL_STATIC_ASSERT(sizeof(void*) == sizeof(stacktrace_entry)); _STL_INTERNAL_STATIC_ASSERT(alignof(void*) == alignof(stacktrace_entry)); return reinterpret_cast(_Frames.data()); } - static unsigned long _Adjust_skip(size_t _Skip) { + _NODISCARD static unsigned long _Adjust_skip(size_t _Skip) noexcept { _Skip += 1; // Skip current frame return _Skip < ULONG_MAX ? static_cast(_Skip) : ULONG_MAX; } From 70122e68f01285880d389da6cf49d44b1fd0cc9e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Jun 2022 18:09:32 -0700 Subject: [PATCH 115/131] Use SRWLOCK_INIT. --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index c6fc573e63..d4cfcbacd7 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -251,7 +251,7 @@ namespace { } public: - inline static SRWLOCK srw; + inline static SRWLOCK srw = SRWLOCK_INIT; private: inline static IDebugClient* debug_client = nullptr; From d0ca01a953f62c247aac8960978ef0eb88820e1e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Jun 2022 18:12:19 -0700 Subject: [PATCH 116/131] Drop debug_symbols3. --- stl/src/stacktrace.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index d4cfcbacd7..2fe6fc9456 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -105,10 +105,6 @@ namespace { (void) debug_control->WaitForEvent(0, INFINITE); } - // If this fails, will use IDebugSymbols - (void) debug_symbols->QueryInterface( - IID_IDebugSymbols3, reinterpret_cast(&debug_symbols3)); - // clang-format off constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ | 0x2 /* SYMOPT_UNDNAME */ @@ -254,13 +250,12 @@ namespace { inline static SRWLOCK srw = SRWLOCK_INIT; private: - inline static IDebugClient* debug_client = nullptr; - inline static IDebugSymbols* debug_symbols = nullptr; - inline static IDebugSymbols3* debug_symbols3 = nullptr; - inline static IDebugControl* debug_control = nullptr; - inline static bool attached = false; - inline static bool initialize_attempted = false; - inline static HMODULE dbgeng = nullptr; + inline static IDebugClient* debug_client = nullptr; + inline static IDebugSymbols* debug_symbols = nullptr; + inline static IDebugControl* debug_control = nullptr; + inline static bool attached = false; + inline static bool initialize_attempted = false; + inline static HMODULE dbgeng = nullptr; }; void lock_and_uninitialize() { From eb9f444da64c3fcc38a140d065c1524d79a013c7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Jun 2022 18:13:00 -0700 Subject: [PATCH 117/131] Allow clang-format to fix indentation. --- stl/src/stacktrace.cpp | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 2fe6fc9456..c14c932a04 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -105,25 +105,23 @@ namespace { (void) debug_control->WaitForEvent(0, INFINITE); } - // clang-format off - constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ - | 0x2 /* SYMOPT_UNDNAME */ - | 0x4 /* SYMOPT_DEFERRED_LOADS */ - | 0x10 /* SYMOPT_LOAD_LINES */ - | 0x20 /* SYMOPT_OMAP_FIND_NEAREST */ - | 0x100 /* SYMOPT_FAIL_CRITICAL_ERRORS */ - | 0x10000 /* SYMOPT_AUTO_PUBLICS */ - | 0x80000 /* SYMOPT_NO_PROMPTS */; - - constexpr ULONG remove_options = 0x8 /* SYMOPT_NO_CPP */ - | 0x40 /* SYMOPT_LOAD_ANYTHING */ - | 0x100 /* SYMOPT_NO_UNQUALIFIED_LOADS */ - | 0x400 /* SYMOPT_EXACT_SYMBOLS */ - | 0x1000 /* SYMOPT_IGNORE_NT_SYMPATH */ - | 0x4000 /* SYMOPT_PUBLICS_ONLY */ - | 0x8000 /* SYMOPT_NO_PUBLICS */ - | 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; - // clang-format on + constexpr ULONG add_options = 0x1 /* SYMOPT_CASE_INSENSITIVE */ + | 0x2 /* SYMOPT_UNDNAME */ + | 0x4 /* SYMOPT_DEFERRED_LOADS */ + | 0x10 /* SYMOPT_LOAD_LINES */ + | 0x20 /* SYMOPT_OMAP_FIND_NEAREST */ + | 0x100 /* SYMOPT_FAIL_CRITICAL_ERRORS */ + | 0x10000 /* SYMOPT_AUTO_PUBLICS */ + | 0x80000 /* SYMOPT_NO_PROMPTS */; + + constexpr ULONG remove_options = 0x8 /* SYMOPT_NO_CPP */ + | 0x40 /* SYMOPT_LOAD_ANYTHING */ + | 0x100 /* SYMOPT_NO_UNQUALIFIED_LOADS */ + | 0x400 /* SYMOPT_EXACT_SYMBOLS */ + | 0x1000 /* SYMOPT_IGNORE_NT_SYMPATH */ + | 0x4000 /* SYMOPT_PUBLICS_ONLY */ + | 0x8000 /* SYMOPT_NO_PUBLICS */ + | 0x20000 /* SYMOPT_NO_IMAGE_SEARCH */; (void) debug_symbols->AddSymbolOptions(add_options); (void) debug_symbols->RemoveSymbolOptions(remove_options); From 9ac0b655b952ac57f233d3989823568eb8c24e69 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Jun 2022 18:23:22 -0700 Subject: [PATCH 118/131] Fix comment: _Callback is what's tested for null. --- stl/inc/stacktrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index bdda2b6b39..d51c43db71 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -30,7 +30,7 @@ _STL_DISABLE_CLANG_WARNINGS // of _Stacktrace_string_fill_callback type to fill the buffer. This is needed to type-erase or , and // make it possible to keep the separately compiled implementation in the import library. // -// Additionally, _Stacktrace_string_fill can be called with nullptr string parameter to determine already reserved +// Additionally, _Stacktrace_string_fill can be called with a null _Callback argument to determine already reserved // string buffer for cases when the size is not known before an attempt to fill it -- this potentially avoids both extra // fill attempt and extra allocation if the reserved size is enough. From 581cfe3eda4045dd1aadd4e7d090742f85afd75f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Jun 2022 18:27:33 -0700 Subject: [PATCH 119/131] Improve comment grammar. --- stl/inc/stacktrace | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index d51c43db71..71106b8dc4 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -25,14 +25,14 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -// The separately compiled part of implementation calls a function pointer of _Stacktrace_string_fill type -// to allocate a buffer for string output. The called function does the buffer allocation and calls a function pointer -// of _Stacktrace_string_fill_callback type to fill the buffer. This is needed to type-erase or , and -// make it possible to keep the separately compiled implementation in the import library. +// The separately compiled part of the implementation calls a function pointer of _Stacktrace_string_fill +// type to allocate a buffer for string output. The called function does the buffer allocation and calls a function +// pointer of _Stacktrace_string_fill_callback type to fill the buffer. This is needed to type-erase or +// , and makes it possible to keep the separately compiled implementation in the import library. // -// Additionally, _Stacktrace_string_fill can be called with a null _Callback argument to determine already reserved -// string buffer for cases when the size is not known before an attempt to fill it -- this potentially avoids both extra -// fill attempt and extra allocation if the reserved size is enough. +// Additionally, _Stacktrace_string_fill can be called with a null _Callback argument to determine the already reserved +// string buffer for cases when the size is not known before an attempt to fill it -- this potentially avoids both an +// extra fill attempt and an extra allocation if the reserved size is enough. using _Stacktrace_string_fill_callback = size_t(__stdcall*)(char* _Data, size_t _Size, void* _Context) _NOEXCEPT_FNPTR; From 524bb81402b185d47b07f7ecd7324115ab76fd1c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 2 Jun 2022 18:50:24 -0700 Subject: [PATCH 120/131] Fuse srw_lock_guard into dbg_eng_data and use non-static member functions to enforce locking. --- stl/src/stacktrace.cpp | 73 +++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index c14c932a04..9314639858 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -32,27 +32,22 @@ namespace { } // TRANSITION, GH-2285. Use SRWLOCK instead of std::mutex to avoid nontrivial constructor and nontrivial destructor - class _NODISCARD srw_lock_guard { + void lock_and_uninitialize(); + + class _NODISCARD dbg_eng_data { public: - explicit srw_lock_guard(SRWLOCK& locked_) noexcept : locked(&locked_) { - AcquireSRWLockExclusive(locked); + dbg_eng_data() noexcept { + AcquireSRWLockExclusive(&srw); } - ~srw_lock_guard() { - ReleaseSRWLockExclusive(locked); + ~dbg_eng_data() { + ReleaseSRWLockExclusive(&srw); } - srw_lock_guard(const srw_lock_guard&) = delete; - srw_lock_guard& operator=(const srw_lock_guard&) = delete; - - private: - SRWLOCK* const locked; - }; + dbg_eng_data(const dbg_eng_data&) = delete; + dbg_eng_data& operator=(const dbg_eng_data&) = delete; - void lock_and_uninitialize(); - - struct dbg_eng_data { - static void uninitialize() { + void uninitialize() { // "Phoenix singleton" - destroy and set to null, so that it can be initialized later again if (debug_client != nullptr) { @@ -83,7 +78,7 @@ namespace { initialize_attempted = false; } - static bool try_initialize() { + bool try_initialize() { if (!initialize_attempted) { dbgeng = LoadLibraryExW(L"dbgeng.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); @@ -139,7 +134,7 @@ namespace { return debug_symbols != nullptr; } - static size_t get_description( + size_t get_description( const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { // Initially pass the current capacity, will retry with bigger buffer if it fails. size_t size = fill(0, str, nullptr, nullptr) - off; @@ -180,7 +175,7 @@ namespace { return off; } - static size_t source_file(const void* const address, void* const str, size_t off, ULONG* const line, + size_t source_file(const void* const address, void* const str, size_t off, ULONG* const line, const _Stacktrace_string_fill fill) { // Initially pass the current capacity, will retry with bigger buffer if fails. size_t size = fill(0, str, nullptr, nullptr) - off; @@ -214,7 +209,7 @@ namespace { return off; } - [[nodiscard]] static unsigned int source_line(const void* const address) { + [[nodiscard]] unsigned int source_line(const void* const address) { ULONG line = 0; if (FAILED(debug_symbols->GetLineByOffset( @@ -225,7 +220,7 @@ namespace { return line; } - static size_t address_to_string( + size_t address_to_string( const void* const address, void* const str, size_t off, const _Stacktrace_string_fill fill) { ULONG line = 0; @@ -244,10 +239,8 @@ namespace { return get_description(address, str, off, fill); } - public: - inline static SRWLOCK srw = SRWLOCK_INIT; - private: + inline static SRWLOCK srw = SRWLOCK_INIT; inline static IDebugClient* debug_client = nullptr; inline static IDebugSymbols* debug_symbols = nullptr; inline static IDebugControl* debug_control = nullptr; @@ -257,9 +250,9 @@ namespace { }; void lock_and_uninitialize() { - const srw_lock_guard lock{dbg_eng_data::srw}; + dbg_eng_data locked_data; - dbg_eng_data::uninitialize(); + locked_data.uninitialize(); } } // namespace @@ -277,52 +270,52 @@ _EXTERN_C void __stdcall __std_stacktrace_description( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { - const srw_lock_guard lock{dbg_eng_data::srw}; + dbg_eng_data locked_data; - if (!dbg_eng_data::try_initialize()) { + if (!locked_data.try_initialize()) { return; } - dbg_eng_data::get_description(_Address, _Str, 0, _Fill); + locked_data.get_description(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_source_file( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { - const srw_lock_guard lock{dbg_eng_data::srw}; + dbg_eng_data locked_data; - if (!dbg_eng_data::try_initialize()) { + if (!locked_data.try_initialize()) { return; } - dbg_eng_data::source_file(_Address, _Str, 0, nullptr, _Fill); + locked_data.source_file(_Address, _Str, 0, nullptr, _Fill); } [[nodiscard]] unsigned int __stdcall __std_stacktrace_source_line(const void* const _Address) noexcept { - const srw_lock_guard lock{dbg_eng_data::srw}; + dbg_eng_data locked_data; - if (!dbg_eng_data::try_initialize()) { + if (!locked_data.try_initialize()) { return 0; } - return dbg_eng_data::source_line(_Address); + return locked_data.source_line(_Address); } void __stdcall __std_stacktrace_address_to_string( const void* const _Address, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { - const srw_lock_guard lock{dbg_eng_data::srw}; + dbg_eng_data locked_data; - if (!dbg_eng_data::try_initialize()) { + if (!locked_data.try_initialize()) { return; } - dbg_eng_data::address_to_string(_Address, _Str, 0, _Fill); + locked_data.address_to_string(_Address, _Str, 0, _Fill); } void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const size_t _Size, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { - const srw_lock_guard lock{dbg_eng_data::srw}; + dbg_eng_data locked_data; - if (!dbg_eng_data::try_initialize()) { + if (!locked_data.try_initialize()) { return; } @@ -346,7 +339,7 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si return off + ret; }); - off = dbg_eng_data::address_to_string(data[i], _Str, off, _Fill); + off = locked_data.address_to_string(data[i], _Str, off, _Fill); } } _END_EXTERN_C From 5071c5eb279dbbf614e25f85252440e7a569e2df Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 3 Jun 2022 10:06:47 +0300 Subject: [PATCH 121/131] more `noexcept` --- stl/inc/stacktrace | 2 +- stl/src/stacktrace.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 71106b8dc4..0191bf4405 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -299,7 +299,7 @@ private: || allocator_traits<_Alloc>::is_always_equal::value; struct _Internal_t { - explicit _Internal_t() = default; + explicit _Internal_t() noexcept = default; }; basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 9314639858..d1114ffa34 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -32,7 +32,7 @@ namespace { } // TRANSITION, GH-2285. Use SRWLOCK instead of std::mutex to avoid nontrivial constructor and nontrivial destructor - void lock_and_uninitialize(); + void lock_and_uninitialize() noexcept; class _NODISCARD dbg_eng_data { public: @@ -47,7 +47,7 @@ namespace { dbg_eng_data(const dbg_eng_data&) = delete; dbg_eng_data& operator=(const dbg_eng_data&) = delete; - void uninitialize() { + void uninitialize() noexcept { // "Phoenix singleton" - destroy and set to null, so that it can be initialized later again if (debug_client != nullptr) { @@ -78,7 +78,7 @@ namespace { initialize_attempted = false; } - bool try_initialize() { + bool try_initialize() noexcept { if (!initialize_attempted) { dbgeng = LoadLibraryExW(L"dbgeng.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); @@ -209,7 +209,7 @@ namespace { return off; } - [[nodiscard]] unsigned int source_line(const void* const address) { + [[nodiscard]] unsigned int source_line(const void* const address) noexcept { ULONG line = 0; if (FAILED(debug_symbols->GetLineByOffset( @@ -249,7 +249,7 @@ namespace { inline static HMODULE dbgeng = nullptr; }; - void lock_and_uninitialize() { + void lock_and_uninitialize() noexcept { dbg_eng_data locked_data; locked_data.uninitialize(); From b6c7c6ec0758757d0e16e9c284352d8c8ab6caf4 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 3 Jun 2022 18:28:22 -0700 Subject: [PATCH 122/131] Call atexit() within `if (!initialize_attempted)`. lock_and_uninitialize() is highly robust to partial initialization, so we can register it immediately. Note that if atexit() fails, we haven't initialized anything, so we don't need to call uninitialize() to clean up. Instead, we can immediately return false. Finally, note that if atexit() fails, we leave initialize_attempted set to true (uninitialize() would unset it), so we will never attempt initialization again. --- stl/src/stacktrace.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index d1114ffa34..7787505c9a 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -80,6 +80,12 @@ namespace { bool try_initialize() noexcept { if (!initialize_attempted) { + initialize_attempted = true; + + if (std::atexit(lock_and_uninitialize) != 0) { + return false; + } + dbgeng = LoadLibraryExW(L"dbgeng.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); if (dbgeng != nullptr) { @@ -124,13 +130,6 @@ namespace { } } - if (std::atexit(lock_and_uninitialize) != 0) { - uninitialize(); - return false; - } - - initialize_attempted = true; - return debug_symbols != nullptr; } From 9354074f62a8fa37cb02e8eb07c525d23ed70e6a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 3 Jun 2022 18:37:02 -0700 Subject: [PATCH 123/131] Mark try_initialize() as [[nodiscard]]; its return value is important. Also use [[nodiscard]] instead of _NODISCARD for dbg_eng_data, to be consistent with other occurrences in this source file. --- stl/src/stacktrace.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 7787505c9a..c5e9e8d419 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -34,7 +34,7 @@ namespace { // TRANSITION, GH-2285. Use SRWLOCK instead of std::mutex to avoid nontrivial constructor and nontrivial destructor void lock_and_uninitialize() noexcept; - class _NODISCARD dbg_eng_data { + class [[nodiscard]] dbg_eng_data { public: dbg_eng_data() noexcept { AcquireSRWLockExclusive(&srw); @@ -78,7 +78,7 @@ namespace { initialize_attempted = false; } - bool try_initialize() noexcept { + [[nodiscard]] bool try_initialize() noexcept { if (!initialize_attempted) { initialize_attempted = true; From afd9eeb0f9a7d9470ffeaa3851b5b4dd92dec5df Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 4 Jun 2022 09:22:44 +0300 Subject: [PATCH 124/131] Update stacktrace.cpp More strict check for initialization --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index c5e9e8d419..a58eb8b131 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -130,7 +130,7 @@ namespace { } } - return debug_symbols != nullptr; + return attached; } size_t get_description( From 8399e65d05139a9132ed2e9d8e836c694b73e16c Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 9 Jun 2022 08:31:09 +0300 Subject: [PATCH 125/131] Safer overflow handling for 32-bit platform Co-authored-by: nicole mazzuca <83086508+strega-nil-ms@users.noreply.github.com> --- stl/inc/stacktrace | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 0191bf4405..f774c62c02 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -313,8 +313,7 @@ private: } _NODISCARD static unsigned long _Adjust_skip(size_t _Skip) noexcept { - _Skip += 1; // Skip current frame - return _Skip < ULONG_MAX ? static_cast(_Skip) : ULONG_MAX; + return _Skip < ULONG_MAX - 1 ? static_cast(_Skip + 1) : ULONG_MAX; } _Frames_t _Frames; From 42cf2485d1f4e238dbafb75b029bec1c5fec5f4d Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 9 Jun 2022 13:14:23 +0300 Subject: [PATCH 126/131] avoid exra ctor --- stl/inc/stacktrace | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index f774c62c02..6df9e149d3 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -145,7 +145,7 @@ public: _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL - return basic_stacktrace{_Internal_t{}, _Al}; + return basic_stacktrace{_Al}; _CATCH_END } @@ -158,7 +158,7 @@ public: _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL - return basic_stacktrace{_Internal_t{}, _Al}; + return basic_stacktrace{_Al}; _CATCH_END } @@ -176,7 +176,7 @@ public: _Result._Frames.resize(_Actual_size); return _Result; _CATCH_ALL - return basic_stacktrace{_Internal_t{}, _Al}; + return basic_stacktrace{_Al}; _CATCH_END } @@ -304,8 +304,6 @@ private: basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} - basic_stacktrace(_Internal_t, const allocator_type& _Al) noexcept : _Frames(_Al) {} - _NODISCARD void** _To_voidptr_array() noexcept { _STL_INTERNAL_STATIC_ASSERT(sizeof(void*) == sizeof(stacktrace_entry)); _STL_INTERNAL_STATIC_ASSERT(alignof(void*) == alignof(stacktrace_entry)); @@ -313,7 +311,7 @@ private: } _NODISCARD static unsigned long _Adjust_skip(size_t _Skip) noexcept { - return _Skip < ULONG_MAX - 1 ? static_cast(_Skip + 1) : ULONG_MAX; + return _Skip < ULONG_MAX - 1 ? static_cast(_Skip + 1) : ULONG_MAX; } _Frames_t _Frames; From 8235667323a5c223261fcc5aa0bbede1e7470925 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 9 Jun 2022 13:18:36 +0300 Subject: [PATCH 127/131] Update stl/inc/stacktrace Co-authored-by: nicole mazzuca <83086508+strega-nil-ms@users.noreply.github.com> --- stl/inc/stacktrace | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 6df9e149d3..08c4d5a726 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -165,12 +165,12 @@ public: _NODISCARD __declspec(noinline) static basic_stacktrace current(const size_type _Skip, size_type _Max_depth, const allocator_type& _Al = allocator_type()) noexcept { _TRY_BEGIN - basic_stacktrace _Result{_Internal_t{}, _Max_depth, _Al}; - if (_Max_depth > _Max_frames) { _Max_depth = _Max_frames; } + basic_stacktrace _Result{_Internal_t{}, _Max_depth, _Al}; + const unsigned short _Actual_size = __std_stacktrace_capture( _Adjust_skip(_Skip), static_cast(_Max_depth), _Result._To_voidptr_array(), &_Result._Hash); _Result._Frames.resize(_Actual_size); From f63eb4db5e9d45d945430fb2dc5a8887044f5a30 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 9 Jun 2022 13:23:31 +0300 Subject: [PATCH 128/131] Update stl/src/stacktrace.cpp Co-authored-by: nicole mazzuca <83086508+strega-nil-ms@users.noreply.github.com> --- stl/src/stacktrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index a58eb8b131..1b4a5a13f5 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -162,7 +162,7 @@ namespace { } if (displacement != 0) { - constexpr size_t max_disp_num = sizeof("+0x1111222233334444") - 1; // maximum possible offset + constexpr size_t max_disp_num = sizeof("+0x1122334455667788") - 1; // maximum possible offset off = string_fill(fill, off + max_disp_num, str, [displacement, off](char* s, size_t) { const int ret = std::snprintf(s + off, max_disp_num, "+0x%llX", displacement); From 35471339bcf3fedfe80f700ce5139ace611decf1 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 9 Jun 2022 14:19:00 +0300 Subject: [PATCH 129/131] TCOnsistent --- stl/src/stacktrace.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 1b4a5a13f5..89f7dbe1de 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -256,13 +256,12 @@ namespace { } // namespace _EXTERN_C +#pragma optimize("", off) // inhibit tail call optimization to have consistent _Frames_to_skip adjustment here [[nodiscard]] unsigned short __stdcall __std_stacktrace_capture(unsigned long _Frames_to_skip, const unsigned long _Frames_to_capture, void** const _Back_trace, unsigned long* const _Back_trace_hash) noexcept { -#ifdef _DEBUG - _Frames_to_skip += 1; // compensate for absence of tail call optimization here -#endif - return CaptureStackBackTrace(_Frames_to_skip, _Frames_to_capture, _Back_trace, _Back_trace_hash); + return CaptureStackBackTrace(_Frames_to_skip + 1, _Frames_to_capture, _Back_trace, _Back_trace_hash); } +#pragma optimize("", on) // end inhibit tail call optimization // Some of these functions may throw (They would propagate bad_alloc potentially thrown from // string::resize_and_overwrite) From 5f280d6d630d673f6dade87b6cde62eb90dca7c2 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 9 Jun 2022 14:36:38 +0300 Subject: [PATCH 130/131] uniform _To_voidptr_array --- stl/inc/stacktrace | 21 +++++++++++---------- stl/src/stacktrace.cpp | 6 ++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index 08c4d5a726..eeb84e0b65 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -58,7 +58,7 @@ void __stdcall __std_stacktrace_source_file( // _NODISCARD unsigned int __stdcall __std_stacktrace_source_line(const void* _Address) noexcept; void __stdcall __std_stacktrace_to_string( - const void* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); + const void* const* _Addresses, size_t _Size, void* _Str, _Stacktrace_string_fill _Fill) noexcept(false); _END_EXTERN_C _STD_BEGIN @@ -288,8 +288,15 @@ public: return _Hash; } - _NODISCARD const void* _Data() const noexcept { - return _Frames.data(); + _STL_INTERNAL_STATIC_ASSERT(sizeof(void*) == sizeof(stacktrace_entry)); + _STL_INTERNAL_STATIC_ASSERT(alignof(void*) == alignof(stacktrace_entry)); + + _NODISCARD const void* const* _To_voidptr_array() const noexcept { + return reinterpret_cast(_Frames.data()); + } + + _NODISCARD void** _To_voidptr_array() noexcept { + return reinterpret_cast(_Frames.data()); } private: @@ -304,12 +311,6 @@ private: basic_stacktrace(_Internal_t, size_type _Max_depth, const allocator_type& _Al) : _Frames(_Max_depth, _Al) {} - _NODISCARD void** _To_voidptr_array() noexcept { - _STL_INTERNAL_STATIC_ASSERT(sizeof(void*) == sizeof(stacktrace_entry)); - _STL_INTERNAL_STATIC_ASSERT(alignof(void*) == alignof(stacktrace_entry)); - return reinterpret_cast(_Frames.data()); - } - _NODISCARD static unsigned long _Adjust_skip(size_t _Skip) noexcept { return _Skip < ULONG_MAX - 1 ? static_cast(_Skip + 1) : ULONG_MAX; } @@ -334,7 +335,7 @@ _NODISCARD inline string to_string(const stacktrace_entry& _Fx) { template _NODISCARD string to_string(const basic_stacktrace<_Alloc>& _St) { string _Result; - __std_stacktrace_to_string(_St._Data(), _St.size(), &_Result, _Stacktrace_string_fill_impl); + __std_stacktrace_to_string(_St._To_voidptr_array(), _St.size(), &_Result, _Stacktrace_string_fill_impl); return _Result; } diff --git a/stl/src/stacktrace.cpp b/stl/src/stacktrace.cpp index 89f7dbe1de..84da66adc9 100644 --- a/stl/src/stacktrace.cpp +++ b/stl/src/stacktrace.cpp @@ -309,7 +309,7 @@ void __stdcall __std_stacktrace_address_to_string( locked_data.address_to_string(_Address, _Str, 0, _Fill); } -void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const size_t _Size, void* const _Str, +void __stdcall __std_stacktrace_to_string(const void* const* const _Addresses, const size_t _Size, void* const _Str, const _Stacktrace_string_fill _Fill) noexcept(false) { dbg_eng_data locked_data; @@ -317,8 +317,6 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si return; } - const auto data = reinterpret_cast(_Addresses); - size_t off = 0; for (size_t i = 0; i != _Size; ++i) { @@ -337,7 +335,7 @@ void __stdcall __std_stacktrace_to_string(const void* const _Addresses, const si return off + ret; }); - off = locked_data.address_to_string(data[i], _Str, off, _Fill); + off = locked_data.address_to_string(_Addresses[i], _Str, off, _Fill); } } _END_EXTERN_C From 6b6a43a262e92792879f152f0884f2fca451c3e7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 11 Jun 2022 02:19:26 -0700 Subject: [PATCH 131/131] Fix internal test harness. --- tests/std/tests/P0881R7_stacktrace/env.lst | 2 +- .../std/tests/P0881R7_stacktrace/postexecute.pl | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/std/tests/P0881R7_stacktrace/postexecute.pl diff --git a/tests/std/tests/P0881R7_stacktrace/env.lst b/tests/std/tests/P0881R7_stacktrace/env.lst index 73e14d5ef4..1349aaccb5 100644 --- a/tests/std/tests/P0881R7_stacktrace/env.lst +++ b/tests/std/tests/P0881R7_stacktrace/env.lst @@ -3,6 +3,6 @@ RUNALL_INCLUDE ..\usual_latest_matrix.lst RUNALL_CROSSLIST -PM_CL="/Zi /DHAS_DEBUG_INFO" +PM_CL="/Zi /DHAS_DEBUG_INFO" PM_LINK="/debug" PM_CL="/DHAS_EXPORT" PM_CL="" diff --git a/tests/std/tests/P0881R7_stacktrace/postexecute.pl b/tests/std/tests/P0881R7_stacktrace/postexecute.pl new file mode 100644 index 0000000000..94076adee7 --- /dev/null +++ b/tests/std/tests/P0881R7_stacktrace/postexecute.pl @@ -0,0 +1,16 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +use strict; +use warnings; + +sub PostExecuteHook() +{ + Run::Delete("P0881R7_stacktrace.exe"); + Run::Delete("P0881R7_stacktrace.exp"); + Run::Delete("P0881R7_stacktrace.lib"); + Run::Delete("P0881R7_stacktrace.pdb"); + Run::Delete("test.obj"); + Run::Delete("vc140.pdb"); +} +1