github-actions[bot] commented on code in PR #64454: URL: https://github.com/apache/doris/pull/64454#discussion_r3417714986
########## be/src/service/http/action/be_thread_stack_action.cpp: ########## @@ -0,0 +1,1024 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "service/http/action/be_thread_stack_action.h" + +#include <fmt/format.h> + +#ifdef __linux__ +#include <fcntl.h> +#include <poll.h> +#include <sys/syscall.h> +#include <ucontext.h> +#include <unistd.h> + +#include <algorithm> +#include <array> +#include <atomic> +#include <cctype> +#include <cerrno> +#include <chrono> +#include <csignal> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <filesystem> +#include <fstream> +#include <limits> +#include <mutex> +#include <optional> +#include <sstream> +#include <string> +#include <string_view> +#include <thread> +#include <vector> +#endif + +#include "common/logging.h" +#include "common/stack_trace.h" +#include "service/http/http_channel.h" +#include "service/http/http_headers.h" +#include "service/http/http_request.h" +#include "service/http/http_status.h" + +namespace doris { + +namespace { + +constexpr std::string_view HEADER_TEXT = "text/plain; charset=utf-8"; + +#ifdef __linux__ + +constexpr int STACK_TRACE_SIGNAL_OFFSET = 6; +constexpr int DEFAULT_TIMEOUT_MS = 100; +constexpr int MAX_TIMEOUT_MS = 10000; +constexpr int DEFAULT_MAX_SIGNAL_THREADS = 8; +constexpr int MAX_SIGNAL_THREADS = 1024; +constexpr size_t MAX_MEMORY_RANGES = 8192; +constexpr std::string_view DEFAULT_DWARF_MODE = "FAST"; + +struct ThreadInfo { + pid_t tid = 0; + std::string name; +}; + +struct MemoryRange { + uintptr_t begin = 0; + uintptr_t end = 0; +}; + +enum class FramePointerStatus { + END_OF_CHAIN, + NO_CONTEXT, + UNSUPPORTED_ARCH, + NO_STACK_RANGE, + INVALID_FRAME_POINTER, + FRAME_LIMIT, +}; + +struct FramePointerCapture { + StackTrace::FramePointers frame_pointers {}; + size_t size = 0; + uintptr_t stack_begin = 0; + uintptr_t stack_end = 0; + FramePointerStatus fp_status = FramePointerStatus::NO_CONTEXT; +}; + +struct ThreadSyscall { + long number = -1; + std::string name; +}; + +std::once_flag g_install_signal_once; +std::mutex g_collect_mutex; +std::atomic<pid_t> g_server_pid {0}; +std::atomic<int> g_sequence {0}; +std::atomic<int> g_active_sequence {0}; +std::atomic<int> g_data_ready_sequence {0}; +std::atomic<bool> g_signal_latch {false}; +FramePointerCapture g_signal_capture; +std::array<MemoryRange, MAX_MEMORY_RANGES> g_memory_ranges {}; +size_t g_memory_range_count = 0; +int g_notification_pipe[2] = {-1, -1}; + +int rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t* info) { + return static_cast<int>(syscall(__NR_rt_tgsigqueueinfo, tgid, tid, sig, info)); +} + +int stack_trace_signal() { + static const int signal = [] { + const int candidate = SIGRTMIN + STACK_TRACE_SIGNAL_OFFSET; + return candidate <= SIGRTMAX ? candidate : -1; + }(); + return signal; +} + +pid_t get_current_tid() { + return static_cast<pid_t>(syscall(SYS_gettid)); +} + +bool read_signal_registers(const ucontext_t* context, uintptr_t* pc, uintptr_t* fp, uintptr_t* sp) { + if (context == nullptr) { + return false; + } + +#if defined(__x86_64__) + *pc = static_cast<uintptr_t>(context->uc_mcontext.gregs[REG_RIP]); + *fp = static_cast<uintptr_t>(context->uc_mcontext.gregs[REG_RBP]); + *sp = static_cast<uintptr_t>(context->uc_mcontext.gregs[REG_RSP]); + return true; +#elif defined(__aarch64__) + *pc = static_cast<uintptr_t>(context->uc_mcontext.pc); + *fp = static_cast<uintptr_t>(context->uc_mcontext.regs[29]); + *sp = static_cast<uintptr_t>(context->uc_mcontext.sp); + return true; +#else + return false; +#endif +} + +bool range_contains(const MemoryRange& range, uintptr_t address) { + return address >= range.begin && address < range.end; +} + +bool frame_record_is_readable(const MemoryRange& range, uintptr_t fp) { + constexpr uintptr_t frame_record_size = sizeof(uintptr_t) * 2; + return fp >= range.begin && fp <= std::numeric_limits<uintptr_t>::max() - frame_record_size && Review Comment: Please reject unaligned frame-pointer values before this helper lets the signal handler reinterpret the address as `const uintptr_t*` below. The register value comes from an asynchronously interrupted thread; if the thread is in third-party code compiled without frame pointers, or in a prologue/epilogue, `rbp`/`x29` can still contain an address inside the stack mapping while not being aligned for `uintptr_t`. The current bounds check accepts that value, and the later dereference at `reinterpret_cast<const uintptr_t*>(current_fp)` is undefined behavior and can fault on strict-alignment builds. Treating unaligned values as `INVALID_FRAME_POINTER` keeps this diagnostic endpoint from being able to crash the BE while collecting a stack. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
