diff --git a/programs/server/Server.cpp b/programs/server/Server.cpp index a80ab05ec4c..1eeec398f44 100644 --- a/programs/server/Server.cpp +++ b/programs/server/Server.cpp @@ -388,7 +388,7 @@ int Server::main(const std::vector & /*args*/) LOG_WARNING(log, "Server was built in debug mode. It will work slowly."); #endif -#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER) +#if defined(SANITIZER) LOG_WARNING(log, "Server was built with sanitizer. It will work slowly."); #endif diff --git a/src/Common/ThreadStatus.cpp b/src/Common/ThreadStatus.cpp index 3215bb55537..4bba3d8f4eb 100644 --- a/src/Common/ThreadStatus.cpp +++ b/src/Common/ThreadStatus.cpp @@ -2,11 +2,14 @@ #include #include #include +#include #include #include #include +#include + namespace DB { @@ -21,6 +24,11 @@ namespace ErrorCodes thread_local ThreadStatus * current_thread = nullptr; thread_local ThreadStatus * main_thread = nullptr; +#if !defined(SANITIZER) && !defined(ARCADIA_BUILD) + alignas(4096) static thread_local char alt_stack[4096]; + static thread_local bool has_alt_stack = false; +#endif + ThreadStatus::ThreadStatus() : thread_id{getThreadId()} @@ -34,6 +42,46 @@ 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. + /// Sanitizer makes larger stack usage and also it's incompatible with alternative stack by default (it sets up and relies on its own). +#if !defined(SANITIZER) && !defined(ARCADIA_BUILD) + 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{}; + altstack_description.ss_sp = alt_stack; + altstack_description.ss_flags = 0; + altstack_description.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)); + } + } + } + } +#endif } ThreadStatus::~ThreadStatus() diff --git a/src/Functions/trap.cpp b/src/Functions/trap.cpp index 34553f4b266..38cf53948e6 100644 --- a/src/Functions/trap.cpp +++ b/src/Functions/trap.cpp @@ -61,9 +61,10 @@ 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(const 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 +136,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 +165,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); } };