Skip to content

Add C++23 stacktrace (P0881R7) #136528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 51 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
d313e19
Add C++23 stacktrace
elsteveogrande Jan 16, 2025
13b6b4f
Remove unrelated change
elsteveogrande Apr 21, 2025
2d69584
fix cflag option
elsteveogrande Apr 23, 2025
ed263ce
Move stacktrace headers out of experimental
elsteveogrande Apr 21, 2025
213017e
Move stacktrace srcs out of experimental
elsteveogrande Apr 22, 2025
99e6db1
simplify layout of stacktrace files: condense, collapse
elsteveogrande Apr 23, 2025
67567cf
Reference papers and issues
elsteveogrande Apr 23, 2025
d7f2629
Updates per PR feedback
elsteveogrande Apr 23, 2025
008ea69
Remove newline at end of file: std.compat.cppm.in
elsteveogrande Apr 23, 2025
4c7c9f4
Committing regenerated files
Apr 23, 2025
17699d9
Address lints for system headers
elsteveogrande Apr 23, 2025
b12cd7f
Add generated 'stacktrace.version.compile.pass.cpp' test
elsteveogrande Apr 23, 2025
f203dc9
Address some errors from gcc regarding inlining
elsteveogrande Apr 23, 2025
8fac222
Feature macros + regenerate
elsteveogrande Apr 24, 2025
41ac845
Break up tests
elsteveogrande Apr 24, 2025
b89fa7a
Minor: formatting
elsteveogrande Apr 24, 2025
83ee2e3
Remove changes not related to this (probably a previous bad merge)
elsteveogrande Apr 24, 2025
2d20c4b
Correcting doc for LIBCXX_STACKTRACE_ALLOW_TOOLS_AT_RUNTIME
elsteveogrande Apr 24, 2025
b4d97e5
Add C++23 stacktrace
elsteveogrande Jan 16, 2025
823f0ba
Remove unrelated change
elsteveogrande Apr 21, 2025
2fd143b
Move stacktrace headers out of experimental
elsteveogrande Apr 21, 2025
f511de2
Move stacktrace srcs out of experimental
elsteveogrande Apr 22, 2025
d9c7698
simplify layout of stacktrace files: condense, collapse
elsteveogrande Apr 23, 2025
140d36a
Updates per PR feedback
elsteveogrande Apr 23, 2025
2428ac5
Remove newline at end of file: std.compat.cppm.in
elsteveogrande Apr 23, 2025
2e6632c
Committing regenerated files
Apr 23, 2025
e0d2b60
Address some errors from gcc regarding inlining
elsteveogrande Apr 23, 2025
7724b01
Feature macros + regenerate
elsteveogrande Apr 24, 2025
f65f5a8
Break up tests
elsteveogrande Apr 24, 2025
ce9bc35
Remove changes not related to this (probably a previous bad merge)
elsteveogrande Apr 24, 2025
0d8ebc6
Mention URL 'format' task (105257) for TODO's
elsteveogrande May 14, 2025
bff8a08
commit new generated files
elsteveogrande May 14, 2025
587951b
formatting
elsteveogrande May 14, 2025
9c5986c
refactor; rework alloc/dealloc, strings; don't use pmr
elsteveogrande May 16, 2025
5b5c49e
regenerated files
elsteveogrande May 19, 2025
408e900
formatting
elsteveogrande May 19, 2025
fdc6b09
formatting
elsteveogrande May 19, 2025
71c4fbc
clean up non-ASCII chars from pasted content
elsteveogrande May 19, 2025
c6b4f19
minor: rename a .cpp
elsteveogrande May 20, 2025
3ea41c6
split up confusing 'utils.h'
elsteveogrande May 20, 2025
2df8911
fix windows macros
elsteveogrande May 20, 2025
ed89357
break up win impl
elsteveogrande May 20, 2025
d5b7e0f
break up other impl's
elsteveogrande May 23, 2025
3f8c40c
cleanup impl's
elsteveogrande May 23, 2025
8499f93
remove placeholder header for formatter
elsteveogrande May 24, 2025
35bc431
end-of-file newline?
elsteveogrande May 24, 2025
524373c
rebase, and push small whitespace-only change on generated file
elsteveogrande Jun 2, 2025
42cb643
update build_stacktrace
elsteveogrande Jun 13, 2025
06fe49f
fix build, needed an instantiation of allocator
elsteveogrande Jun 13, 2025
d9040e9
formatting
elsteveogrande Jun 14, 2025
24dcdfc
formatting
elsteveogrande Jun 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions libcxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
the shared library they shipped should turn this on and see `include/__configuration/availability.h`
for more details." OFF)

option(LIBCXX_STACKTRACE_ALLOW_TOOLS_AT_RUNTIME
"For C++23 <stacktrace>: whether to allow invocation of `addr2line`, `llvm-addr2line`, or `atos`
at runtime (if it's available in `PATH`) to resolve call-chain addresses in the stacktrace
into source locations, if other methods are not available." ON)

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in")
elseif(MINGW)
Expand Down Expand Up @@ -758,6 +763,7 @@ config_define(${LIBCXX_ENABLE_UNICODE} _LIBCPP_HAS_UNICODE)
config_define(${LIBCXX_ENABLE_WIDE_CHARACTERS} _LIBCPP_HAS_WIDE_CHARACTERS)
config_define(${LIBCXX_ENABLE_TIME_ZONE_DATABASE} _LIBCPP_HAS_TIME_ZONE_DATABASE)
config_define(${LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS} _LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS)
config_define(${LIBCXX_STACKTRACE_ALLOW_TOOLS_AT_RUNTIME} _LIBCPP_STACKTRACE_ALLOW_TOOLS_AT_RUNTIME)

# TODO: Remove in LLVM 21. We're leaving an error to make this fail explicitly.
if (LIBCXX_ENABLE_ASSERTIONS)
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_spanstream`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_stacktrace`` *unimplemented*
``__cpp_lib_stacktrace`` ``202011L``
---------------------------------------------------------- -----------------
``__cpp_lib_stdatomic_h`` ``202011L``
---------------------------------------------------------- -----------------
Expand Down
2 changes: 2 additions & 0 deletions libcxx/docs/ReleaseNotes/21.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ Implemented Papers
- P1222R4: A Standard ``flat_set`` (`Github <https://github.com/llvm/llvm-project/issues/105193>`__)
- P2897R7: ``aligned_accessor``: An mdspan accessor expressing pointer over-alignment (`Github <https://github.com/llvm/llvm-project/issues/118372>`__)
- P3247R2: Deprecate the notion of trivial types (`Github <https://github.com/llvm/llvm-project/issues/118387>`__)
- P0881R7: A Proposal to add stacktrace library (`Github <https://github.com/llvm/llvm-project/issues/105131>`__)
- P2301R1: Add a `pmr` alias for `std::stacktrace` (`Github <https://github.com/llvm/llvm-project/issues/105167>`__)

Improvements and New Features
-----------------------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx23Issues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@
"`LWG3028 <https://wg21.link/LWG3028>`__","Container requirements tables should distinguish ``const`` and non-``const`` variables","2022-11 (Kona)","","",""
"`LWG3118 <https://wg21.link/LWG3118>`__","``fpos`` equality comparison unspecified","2022-11 (Kona)","","",""
"`LWG3177 <https://wg21.link/LWG3177>`__","Limit permission to specialize variable templates to program-defined types","2022-11 (Kona)","|Nothing To Do|","",""
"`LWG3515 <https://wg21.link/LWG3515>`__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized","2022-11 (Kona)","","",""
"`LWG3515 <https://wg21.link/LWG3515>`__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized","2022-11 (Kona)","|Nothing To Do|","",""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only had a quick look but I think the status should be |Complete| and you also need to add Closes #104998 .

#104998

We don't add an entry to Release Notes for LWG issues.

"`LWG3545 <https://wg21.link/LWG3545>`__","``std::pointer_traits`` should be SFINAE-friendly","2022-11 (Kona)","|Complete|","18",""
"`LWG3569 <https://wg21.link/LWG3569>`__","``join_view`` fails to support ranges of ranges with non-default_initializable iterators","2022-11 (Kona)","","",""
"`LWG3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor","2022-11 (Kona)","|Complete|","19",""
Expand Down
6 changes: 3 additions & 3 deletions libcxx/docs/Status/Cxx23Papers.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"Paper #","Paper Name","Meeting","Status","First released version","Notes"
"`P0881R7 <https://wg21.link/P0881R7>`__","A Proposal to add stacktrace library","2020-11 (Virtual)","","",""
"`P0881R7 <https://wg21.link/P0881R7>`__","A Proposal to add stacktrace library","2020-11 (Virtual)","|Complete|","21",""
"`P0943R6 <https://wg21.link/P0943R6>`__","Support C atomics in C++","2020-11 (Virtual)","|Complete|","15",""
"`P1048R1 <https://wg21.link/P1048R1>`__","A proposal for a type trait to detect scoped enumerations","2020-11 (Virtual)","|Complete|","12",""
"`P1679R3 <https://wg21.link/P1679R3>`__","string contains function","2020-11 (Virtual)","|Complete|","12",""
Expand Down Expand Up @@ -32,7 +32,7 @@
"`P1675R2 <https://wg21.link/P1675R2>`__","``rethrow_exception`` must be allowed to copy","2021-10 (Virtual)","|Nothing To Do|","",""
"`P2077R3 <https://wg21.link/P2077R3>`__","Heterogeneous erasure overloads for associative containers","2021-10 (Virtual)","","",""
"`P2251R1 <https://wg21.link/P2251R1>`__","Require ``span`` & ``basic_string_view`` to be Trivially Copyable","2021-10 (Virtual)","|Complete|","14",""
"`P2301R1 <https://wg21.link/P2301R1>`__","Add a ``pmr`` alias for ``std::stacktrace``","2021-10 (Virtual)","","",""
"`P2301R1 <https://wg21.link/P2301R1>`__","Add a ``pmr`` alias for ``std::stacktrace``","2021-10 (Virtual)","|Complete|","21",""
"`P2321R2 <https://wg21.link/P2321R2>`__","``zip``","2021-10 (Virtual)","|In Progress|","",""
"`P2340R1 <https://wg21.link/P2340R1>`__","Clarifying the status of the 'C headers'","2021-10 (Virtual)","|Nothing To Do|","",""
"`P2393R1 <https://wg21.link/P2393R1>`__","Cleaning up ``integer``-class types","2021-10 (Virtual)","","",""
Expand Down Expand Up @@ -110,7 +110,7 @@
"`P2713R1 <https://wg21.link/P2713R1>`__","Escaping improvements in ``std::format``","2023-02 (Issaquah)","|Complete|","19",""
"`P2675R1 <https://wg21.link/P2675R1>`__","``format``'s width estimation is too approximate and not forward compatible","2023-02 (Issaquah)","|Complete|","17",""
"`P2572R1 <https://wg21.link/P2572R1>`__","``std::format`` fill character allowances","2023-02 (Issaquah)","|Complete|","17",""
"`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``","2023-02 (Issaquah)","|Partial|","","The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is not implemented yet"
"`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``","2023-02 (Issaquah)","|Partial|","","The formatter for ``stacktrace`` is not implemented yet"
"`P2679R2 <https://wg21.link/P2679R2>`__","Fixing ``std::start_lifetime_as`` for arrays","2023-02 (Issaquah)","","",""
"`P2674R1 <https://wg21.link/P2674R1>`__","A trait for implicit lifetime types","2023-02 (Issaquah)","|Complete|","20",""
"`P2655R3 <https://wg21.link/P2655R3>`__","``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type","2023-02 (Issaquah)","","",""
Expand Down
8 changes: 8 additions & 0 deletions libcxx/docs/VendorDocumentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,14 @@ General purpose options
ship the IANA time zone database. When time zones are not supported,
time zone support in <chrono> will be disabled.

.. option:: LIBCXX_STACKTRACE_ALLOW_TOOLS_AT_RUNTIME:BOOL

**Default**: ``ON``

For C++23 <stacktrace>: whether to allow invocation of ``addr2line``, ``llvm-addr2line``, or ``atos``
at runtime (if it's available in ``PATH``) to resolve call-chain addresses in the stacktrace
into source locations, if other methods are not available.

.. option:: LIBCXX_INSTALL_LIBRARY_DIR:PATH

**Default**: ``lib${LIBCXX_LIBDIR_SUFFIX}``
Expand Down
7 changes: 7 additions & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,12 @@ set(files
__ranges/views.h
__ranges/zip_view.h
__split_buffer
__stacktrace/base.h
__stacktrace/basic.h
__stacktrace/entry.h
__stacktrace/hash.h
__stacktrace/nonmem.h
__stacktrace/to_string.h
__std_mbstate_t.h
__stop_token/atomic_unique_lock.h
__stop_token/intrusive_list_view.h
Expand Down Expand Up @@ -1047,6 +1053,7 @@ set(files
span
sstream
stack
stacktrace
stdatomic.h
stdbool.h
stddef.h
Expand Down
27 changes: 27 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,33 @@ typedef __char32_t char32_t;
# define _LIBCPP_NOINLINE
# endif

// Some functions, e.g. std::stacktrace::current, need to avoid being
// tail-called by (and tail-calling other) functions, for proper enumeration of
// call-stack frames.
// clang-format off

// Disables tail-call optimization for "outbound" calls
// performed in the function annotated with this attribute.
# if __has_cpp_attribute(_Clang::__disable_tail_calls__)
# define _LIBCPP_NO_TAIL_CALLS_OUT [[_Clang::__disable_tail_calls__]]
# elif __has_cpp_attribute(__gnu__::__optimize__)
# define _LIBCPP_NO_TAIL_CALLS_OUT [[__gnu__::__optimize__("no-optimize-sibling-calls")]]
# else
# define _LIBCPP_NO_TAIL_CALLS_OUT
# endif

// Disables tail-call optimization for "inbound" calls -- that is,
// calls from some other function calling the one having this attribute.
# if __has_cpp_attribute(_Clang::__not_tail_called__)
# define _LIBCPP_NO_TAIL_CALLS_IN [[_Clang::__not_tail_called__]]
# else
# define _LIBCPP_NO_TAIL_CALLS_IN
# endif

// Disable TCO for calls into, and out from, the annotated function.
# define _LIBCPP_NO_TAIL_CALLS _LIBCPP_NO_TAIL_CALLS_IN _LIBCPP_NO_TAIL_CALLS_OUT
// clang-format on

// We often repeat things just for handling wide characters in the library.
// When wide characters are disabled, it can be useful to have a quick way of
// disabling it without having to resort to #if-#endif, which has a larger
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/__config_site.in
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#cmakedefine _LIBCPP_HAS_NO_STD_MODULES
#cmakedefine01 _LIBCPP_HAS_TIME_ZONE_DATABASE
#cmakedefine01 _LIBCPP_INSTRUMENTED_WITH_ASAN
#cmakedefine01 _LIBCPP_STACKTRACE_ALLOW_TOOLS_AT_RUNTIME

// PSTL backends
#cmakedefine _LIBCPP_PSTL_BACKEND_SERIAL
Expand Down
131 changes: 131 additions & 0 deletions libcxx/include/__stacktrace/base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP_STACKTRACE_BUILDER
#define _LIBCPP_STACKTRACE_BUILDER

#include <__config>
#include <__cstddef/byte.h>
#include <__cstddef/size_t.h>
#include <__functional/function.h>
#include <__fwd/format.h>
#include <__fwd/ostream.h>
#include <__memory/allocator_traits.h>
#include <__vector/vector.h>
#include <cstddef>
#include <cstdint>
#include <list>
#include <optional>
#include <string>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

class stacktrace_entry;

namespace __stacktrace {

struct _LIBCPP_HIDE_FROM_ABI alloc final {
function<byte*(size_t)> __alloc_bytes_;
function<void(byte*, size_t)> __dealloc_bytes_;

template <class _Allocator>
alloc(_Allocator __alloc) {
using _AT = allocator_traits<_Allocator>;
using _BA = typename _AT::template rebind_alloc<byte>;
auto __ba = _BA(__alloc);
__alloc_bytes_ = [__ba](size_t __sz) mutable { return __ba.allocate(__sz); };
__dealloc_bytes_ = [__ba](void* __ptr, size_t __sz) mutable { __ba.deallocate((byte*)__ptr, __sz); };
}

template <typename _Tp>
struct Alloc {
function<byte*(size_t)> __alloc_bytes_;
function<void(byte*, size_t)> __dealloc_bytes_;

Alloc(function<byte*(size_t)> __alloc_bytes, function<void(byte*, size_t)> __dealloc_bytes)
: __alloc_bytes_(__alloc_bytes), __dealloc_bytes_(__dealloc_bytes) {}

template <typename _T2 = _Tp>
Alloc(Alloc<_T2> const& __rhs) : Alloc(__rhs.__alloc_bytes_, __rhs.__dealloc_bytes_) {}

using value_type = _Tp;
[[nodiscard]] _Tp* allocate(size_t __sz) { return (_Tp*)__alloc_bytes_(__sz * sizeof(_Tp)); }
void deallocate(_Tp* __ptr, size_t __sz) { __dealloc_bytes_((byte*)__ptr, __sz * sizeof(_Tp)); }

template <typename _A2>
bool operator==(_A2 const& __rhs) const {
return &__rhs == this;
}
};

template <typename _Tp>
Alloc<_Tp> make_alloc() {
return {__alloc_bytes_, __dealloc_bytes_};
}

using str = basic_string<char, char_traits<char>, Alloc<char>>;

template <typename... _Args>
str make_str(_Args... __args) {
return str(std::forward<_Args>(__args)..., make_alloc<char>());
}

template <typename _Tp>
using vec = vector<_Tp, Alloc<_Tp>>;

template <typename _Tp, typename... _Args>
vec<_Tp> make_vec(_Args... __args) {
return vec(std::forward<_Args>(__args)..., make_alloc<_Tp>());
}

template <typename _Tp>
using list = ::std::list<_Tp, Alloc<_Tp>>;

template <typename _Tp, typename... _Args>
list<_Tp> make_list(_Args... __args) {
return list(std::forward<_Args>(__args)..., make_alloc<_Tp>());
}
};

struct _LIBCPP_HIDE_FROM_ABI entry_base {
uintptr_t __addr_actual_{}; // this address, as observed in this current process
uintptr_t __addr_unslid_{}; // address adjusted for ASLR
optional<__stacktrace::alloc::str> __desc_{}; // uses wrapped _Allocator from caller
optional<__stacktrace::alloc::str> __file_{}; // uses wrapped _Allocator from caller
uint_least32_t __line_{};

stacktrace_entry to_stacktrace_entry() const;
};

struct _LIBCPP_HIDE_FROM_ABI builder final {
alloc __alloc_; // wraps the caller-provided allocator
alloc::vec<entry_base> __entries_;
alloc::str __main_prog_path_;

template <class _Allocator>
explicit builder(_Allocator __alloc)
: __alloc_(__alloc), __entries_(__alloc_.make_vec<entry_base>()), __main_prog_path_(__alloc_.make_str()) {}

_LIBCPP_NO_TAIL_CALLS _LIBCPP_NOINLINE _LIBCPP_EXPORTED_FROM_ABI void
build_stacktrace(size_t __skip, size_t __max_depth);
};

} // namespace __stacktrace
_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP_STACKTRACE_BUILDER
Loading
Loading