From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 7549A385CFDF for ; Mon, 11 Apr 2022 17:01:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7549A385CFDF Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-468-VbHbWkGiNLmfKqH_88sdRQ-1; Mon, 11 Apr 2022 13:01:25 -0400 X-MC-Unique: VbHbWkGiNLmfKqH_88sdRQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8E75F8037A4; Mon, 11 Apr 2022 17:01:25 +0000 (UTC) Received: from localhost (unknown [10.33.36.45]) by smtp.corp.redhat.com (Postfix) with ESMTP id 59FDE145B989; Mon, 11 Apr 2022 17:01:25 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Improve behaviour of std::stacktrace::current Date: Mon, 11 Apr 2022 18:01:24 +0100 Message-Id: <20220411170124.169564-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Apr 2022 17:01:29 -0000 Tested x86_64-linux, pushed to trunk. -- >8 -- This prevents inlining the current() function to guarantee that it is present in the stacktrace, then tells libbacktrace to skip that frame. To avoid overflow in the int argument to __glibcxx_backtrace_simple, we need to check if the skip parameter exceeds INT_MAX (which is possible for 16-bit targets where short and int have the same width). We also need to limit the size of the returned value to the max_depth parameter, which was missing previously. This also fixes basic_stacktrace::max_size() to not exceed the maximum size supported by the allocator, which might be smaller than the maximum value of size_type. libstdc++-v3/ChangeLog: * include/std/stacktrace (basic_stacktrace::current): Duplicate implementation into each overload. Add noinline attribute and skip current frame. (basic_stacktrace::max_size()): Call _Impl::_S_max_size. (basic_stacktrace::_S_curr_cb()): New function defining lambda. (basic_stacktrace::_Impl::_S_max_size): New function defining maximum size in terms of allocator and size_type. (basic_stacktrace::_Impl::_M_allocate): Check against max_size(). * testsuite/19_diagnostics/stacktrace/entry.cc: Call function for non-constexpr checks. Check line number is correct. --- libstdc++-v3/include/std/stacktrace | 91 ++++++++++++++----- .../19_diagnostics/stacktrace/entry.cc | 7 +- 2 files changed, 73 insertions(+), 25 deletions(-) diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index 623f44bdca4..4e271cef3f3 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -36,6 +36,7 @@ #include #include #include +#include #include struct __glibcxx_backtrace_state; @@ -232,19 +233,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // [stacktrace.basic.ctor], creation and assignment + [[__gnu__::__noinline__]] static basic_stacktrace current(const allocator_type& __alloc = allocator_type()) noexcept { - return current(0, size_type(-1), __alloc); + auto __state = stacktrace_entry::_S_init(); + basic_stacktrace __ret(__alloc); + if (!__ret._M_reserve(64)) [[unlikely]] + return __ret; + + if (__glibcxx_backtrace_simple(__state, 1, _S_curr_cb(), + nullptr, std::__addressof(__ret))) + __ret._M_clear(); + + return __ret; } + [[__gnu__::__noinline__]] static basic_stacktrace current(size_type __skip, const allocator_type& __alloc = allocator_type()) noexcept { - return current(__skip, size_type(-1), __alloc); + auto __state = stacktrace_entry::_S_init(); + basic_stacktrace __ret(__alloc); + if (__skip >= __INT_MAX__) [[unlikely]] + return __ret; + if (!__ret._M_reserve(64)) [[unlikely]] + return __ret; + + if (__glibcxx_backtrace_simple(__state, __skip + 1, _S_curr_cb(), + nullptr, std::__addressof(__ret))) + __ret._M_clear(); + + return __ret; } + [[__gnu__::__noinline__]] static basic_stacktrace current(size_type __skip, size_type __max_depth, const allocator_type& __alloc = allocator_type()) noexcept @@ -253,23 +277,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __state = stacktrace_entry::_S_init(); basic_stacktrace __ret(__alloc); - if (!__ret._M_reserve(std::min(__max_depth, 64))) + if (__max_depth == 0 || __skip >= __INT_MAX__) [[unlikely]] + return __ret; + if (!__ret._M_reserve(std::min(__max_depth, 64))) [[unlikely]] return __ret; - auto __cb = [](void* __data, uintptr_t __pc) { - auto& __s = *static_cast(__data); - stacktrace_entry __f; - __f._M_pc = __pc; - if (__s._M_push_back(__f)) - return 0; - return 1; - }; + if (__glibcxx_backtrace_simple(__state, __skip + 1, _S_curr_cb(), + nullptr, std::__addressof(__ret))) + __ret._M_clear(); + else if (__ret.size() > __max_depth) + __ret.resize(__max_depth); - if (__glibcxx_backtrace_simple(__state, __skip, +__cb, nullptr, - std::__addressof(__ret))) - { - __ret._M_clear(); - } return __ret; } @@ -443,7 +461,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[nodiscard]] bool empty() const noexcept { return size() == 0; } size_type size() const noexcept { return _M_impl._M_size; } - size_type max_size() const noexcept { return size_type(-1); } + + size_type + max_size() const noexcept + { return _Impl::_S_max_size(_M_impl._M_alloc); } const_reference operator[](size_type __n) const noexcept @@ -507,6 +528,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_impl._M_deallocate(_M_alloc); } + static auto + _S_curr_cb() noexcept + -> int (*) (void*, uintptr_t) + { + return [](void* __data, uintptr_t __pc) { + auto& __s = *static_cast(__data); + stacktrace_entry __f; + __f._M_pc = __pc; + if (__s._M_push_back(__f)) + return 0; + return 1; + }; + } + struct _Impl { using pointer = typename _AllocTraits::pointer; @@ -515,21 +550,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION size_type _M_size = 0; size_type _M_capacity = 0; + static size_type + _S_max_size(const allocator_type& __alloc) noexcept + { + const size_t __size_max = __gnu_cxx::__int_traits::__max; + const size_t __alloc_max = _AllocTraits::max_size(__alloc); + return std::min(__size_max, __alloc_max); + } + // Precondition: _M_frames == nullptr pointer _M_allocate(allocator_type& __alloc, size_type __n) noexcept { __try { - _M_frames = __n ? __alloc.allocate(__n) : nullptr; - _M_capacity = __n; + if (0 < __n && __n <= _S_max_size(__alloc)) [[unlikely]] + { + _M_frames = __alloc.allocate(__n); + _M_capacity = __n; + return _M_frames; + } } __catch (...) { - _M_frames = nullptr; - _M_capacity = 0; } - return _M_frames; + _M_frames = nullptr; + _M_capacity = 0; + return nullptr;; } void diff --git a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc index 0bbcabd8fae..a222c425b20 100644 --- a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc +++ b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc @@ -36,7 +36,8 @@ test_members() VERIFY( e1 != e2 ); VERIFY( e1.description() == e2.description() ); VERIFY( e1.source_file() == e2.source_file() ); - VERIFY( e1.source_line() != e2.source_line() ); + VERIFY( e1.source_line() == (__LINE__ - 5) ); + VERIFY( e2.source_line() == (__LINE__ - 5) ); std::stacktrace_entry e3 = []{ return std::stacktrace::current().at(0); @@ -44,10 +45,10 @@ test_members() VERIFY( e1 != e3 ); VERIFY( e1.description() != e3.description() ); VERIFY( e1.source_file() == e3.source_file() ); - VERIFY( e1.source_line() != e3.source_line() ); + VERIFY( e3.source_line() == (__LINE__ - 5) ); } int main() { - test_constexpr(); + test_members(); } -- 2.34.1