diff --git a/src/Common/ThreadStatus.cpp b/src/Common/ThreadStatus.cpp index bac0559fc6b..7c62117af2f 100644 --- a/src/Common/ThreadStatus.cpp +++ b/src/Common/ThreadStatus.cpp @@ -4,10 +4,13 @@ #include #include #include +#include #include #include +#include + namespace DB { @@ -22,6 +25,9 @@ namespace ErrorCodes thread_local ThreadStatus * current_thread = nullptr; thread_local ThreadStatus * main_thread = nullptr; +alignas(4096) static thread_local char alt_stack[4096]; +static thread_local bool has_alt_stack = false; + ThreadStatus::ThreadStatus() : thread_id{getThreadId()} @@ -35,6 +41,39 @@ ThreadStatus::ThreadStatus() /// NOTE: It is important not to do any non-trivial actions (like updating ProfileEvents or logging) before ThreadStatus is created /// Otherwise it could lead to SIGSEGV due to current_thread dereferencing + + /// Will set alternative signal stack to provide diagnostics for stack overflow errors. + /// If not already installed for current thread. + if (!has_alt_stack) + { + /// Don't repeat tries even if not installed successfully. + has_alt_stack = true; + + /// We have to call 'sigaltstack' before first 'sigaction'. (It does not work other way, for unknown reason). + stack_t altstack_description{ .ss_sp = alt_stack, .ss_flags = 0, .ss_size = sizeof(alt_stack) }; + if (0 != sigaltstack(&altstack_description, nullptr)) + { + LOG_WARNING(log, "Cannot set alternative signal stack for thread, {}", errnoToString(errno)); + } + else + { + /// Obtain existing sigaction and modify it by adding a flag. + struct sigaction action{}; + if (0 != sigaction(SIGSEGV, nullptr, &action)) + { + LOG_WARNING(log, "Cannot obtain previous signal action to set alternative signal stack for thread, {}", errnoToString(errno)); + } + else if (!(action.sa_flags & SA_ONSTACK)) + { + action.sa_flags |= SA_ONSTACK; + + if (0 != sigaction(SIGSEGV, &action, nullptr)) + { + LOG_WARNING(log, "Cannot set action with alternative signal stack for thread, {}", errnoToString(errno)); + } + } + } + } } ThreadStatus::~ThreadStatus() diff --git a/src/Functions/trap.cpp b/src/Functions/trap.cpp index 34553f4b266..505e16411cc 100644 --- a/src/Functions/trap.cpp +++ b/src/Functions/trap.cpp @@ -61,9 +61,9 @@ public: return std::make_shared(); } - [[clang::optnone]] void executeImpl(Block & columns, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) const override + [[clang::optnone]] ColumnPtr executeImpl(ColumnsWithTypeAndName & block, const DataTypePtr & result_type, size_t input_rows_count) const override { - if (const ColumnConst * column = checkAndGetColumnConst(columns[arguments[0]].column.get())) + if (const ColumnConst * column = checkAndGetColumnConst(block[0].column.get())) { String mode = column->getValue(); @@ -135,6 +135,10 @@ public: { (void)context.getCurrentQueryId(); } + else if (mode == "stack overflow") + { + executeImpl(block, result_type, input_rows_count); + } else if (mode == "mmap many") { std::vector maps; @@ -160,7 +164,7 @@ public: else throw Exception("The only argument for function " + getName() + " must be constant String", ErrorCodes::ILLEGAL_COLUMN); - columns[result].column = columns[result].type->createColumnConst(input_rows_count, 0ULL); + return result_type->createColumnConst(input_rows_count, 0ULL); } };