From 3e8310daac8a230694746a1ccaa9040952e14dba Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Wed, 21 Oct 2026 19:45:48 +0300 Subject: [PATCH 1/2] prevent possible segfaults in backtraces --- cmake/utils.cmake | 2 ++ common/fast-backtrace.cpp | 17 +++++++++++++---- runtime-light/stdlib/diagnostics/backtrace.cpp | 13 ++++++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index b8a9a75419..c5ad776c6c 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -285,6 +285,8 @@ function(make_third_party_configuration PIC_ENABLED PROJECT_GENERIC_NAME PROJECT set(${OUT_LIB_SPECIFIER} ${NO_PIC_LIBRARY_SPECIFIER} PARENT_SCOPE) endif() + set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -fno-omit-frame-pointer") + if(COMPILE_RUNTIME_LIGHT) set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} ${RUNTIME_LIGHT_VISIBILITY}") endif() diff --git a/common/fast-backtrace.cpp b/common/fast-backtrace.cpp index 644ba0c4fd..7fef512091 100644 --- a/common/fast-backtrace.cpp +++ b/common/fast-backtrace.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "common/sanitizer.h" @@ -43,9 +44,13 @@ int fast_backtrace(void** buffer, int size) { } int fast_backtrace_by_bp(void* bp, void* stack_end_, void** buffer, int size) { - stack_frame* current_bp = static_cast(bp); + if (stack_end_ == nullptr) { + return 0; + } + const auto last_frame_addr = reinterpret_cast(stack_end_) - sizeof(stack_frame); + auto* current_bp = static_cast(bp); int i = 0; - while (i < size && reinterpret_cast(current_bp) <= stack_end_ && !(reinterpret_cast(current_bp) & (sizeof(long) - 1))) { + while (i < size && reinterpret_cast(current_bp) <= last_frame_addr && !(reinterpret_cast(current_bp) & (sizeof(long) - 1))) { void* ip = current_bp->ip; buffer[i++] = ip; stack_frame* p = current_bp->bp; @@ -67,9 +72,13 @@ int fast_backtrace_without_recursions(void** buffer, int size) noexcept { } int fast_backtrace_without_recursions_by_bp(void* bp, void* stack_end_, void** buffer, int size) noexcept { - stack_frame* current_bp = static_cast(bp); + if (stack_end_ == nullptr) { + return 0; + } + const auto last_frame_addr = reinterpret_cast(stack_end_) - sizeof(stack_frame); + auto* current_bp = static_cast(bp); int i = 0; - while (i < size && reinterpret_cast(current_bp) <= stack_end_ && !(reinterpret_cast(current_bp) & (sizeof(long) - 1))) { + while (i < size && reinterpret_cast(current_bp) <= last_frame_addr && !(reinterpret_cast(current_bp) & (sizeof(long) - 1))) { buffer[i++] = current_bp->ip; for (int possible_recursion_len = 1; i >= 2 * possible_recursion_len; ++possible_recursion_len) { if (std::equal(buffer + i - possible_recursion_len, buffer + i, buffer + i - possible_recursion_len * 2)) { diff --git a/runtime-light/stdlib/diagnostics/backtrace.cpp b/runtime-light/stdlib/diagnostics/backtrace.cpp index 5d11fb0771..7ccc2fc74e 100644 --- a/runtime-light/stdlib/diagnostics/backtrace.cpp +++ b/runtime-light/stdlib/diagnostics/backtrace.cpp @@ -3,6 +3,7 @@ // Distributed under the GPL v3 License, see LICENSE.notice.txt #include +#include #include #include @@ -14,14 +15,24 @@ namespace { +bool is_aligned(const void* ptr, std::size_t alignment) noexcept { + return (reinterpret_cast(ptr) & (alignment - 1)) == 0; +} + size_t sync_frames(std::span addresses, kphp::coro::stack_frame* start_frame, kphp::coro::stack_frame* stop_frame) noexcept { kphp::log::assertion(start_frame != nullptr && stop_frame != nullptr); auto address{addresses.begin()}; - for (auto* current_stack_frame{start_frame}; current_stack_frame != stop_frame && address != addresses.end(); + for (auto* current_stack_frame{start_frame}; + address != addresses.end() && reinterpret_cast(current_stack_frame) < reinterpret_cast(stop_frame) && + is_aligned(current_stack_frame, alignof(void*)); current_stack_frame = current_stack_frame->caller_stack_frame) { *address = current_stack_frame->return_address; address = std::next(address); + auto* next{current_stack_frame->caller_stack_frame}; + if (reinterpret_cast(next) <= reinterpret_cast(current_stack_frame)) { + break; + } } return std::distance(addresses.begin(), address); } From 5b66b8bfb5738a0b5cef08b948466e30d008bef6 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 22 Oct 2026 19:07:21 +0300 Subject: [PATCH 2/2] Use std::uintptr_t for pointer reinterpretation --- common/fast-backtrace.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/fast-backtrace.cpp b/common/fast-backtrace.cpp index 7fef512091..e89d738238 100644 --- a/common/fast-backtrace.cpp +++ b/common/fast-backtrace.cpp @@ -47,10 +47,10 @@ int fast_backtrace_by_bp(void* bp, void* stack_end_, void** buffer, int size) { if (stack_end_ == nullptr) { return 0; } - const auto last_frame_addr = reinterpret_cast(stack_end_) - sizeof(stack_frame); + const auto last_frame_addr = reinterpret_cast(stack_end_) - sizeof(stack_frame); auto* current_bp = static_cast(bp); int i = 0; - while (i < size && reinterpret_cast(current_bp) <= last_frame_addr && !(reinterpret_cast(current_bp) & (sizeof(long) - 1))) { + while (i < size && reinterpret_cast(current_bp) <= last_frame_addr && !(reinterpret_cast(current_bp) & (sizeof(long) - 1))) { void* ip = current_bp->ip; buffer[i++] = ip; stack_frame* p = current_bp->bp; @@ -75,10 +75,10 @@ int fast_backtrace_without_recursions_by_bp(void* bp, void* stack_end_, void** b if (stack_end_ == nullptr) { return 0; } - const auto last_frame_addr = reinterpret_cast(stack_end_) - sizeof(stack_frame); + const auto last_frame_addr = reinterpret_cast(stack_end_) - sizeof(stack_frame); auto* current_bp = static_cast(bp); int i = 0; - while (i < size && reinterpret_cast(current_bp) <= last_frame_addr && !(reinterpret_cast(current_bp) & (sizeof(long) - 1))) { + while (i < size && reinterpret_cast(current_bp) <= last_frame_addr && !(reinterpret_cast(current_bp) & (sizeof(long) - 1))) { buffer[i++] = current_bp->ip; for (int possible_recursion_len = 1; i >= 2 * possible_recursion_len; ++possible_recursion_len) { if (std::equal(buffer + i - possible_recursion_len, buffer + i, buffer + i - possible_recursion_len * 2)) {