From 26b0be5bbc9a8a0b9d265940ba2f09e92ed09e39 Mon Sep 17 00:00:00 2001 From: stribog Date: Sun, 14 Jun 2026 17:33:09 +0200 Subject: [PATCH] =?UTF-8?q?feat(crash):=20=D0=BF=D0=BE=D0=B4=D0=BD=D0=B8?= =?UTF-8?q?=D0=BC=D0=B0=D1=82=D1=8C=20RLIMIT=5FCORE=20=D0=B8=20=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20core?= =?UTF-8?q?=5Fpattern=20=D0=BF=D1=80=D0=B8=20=D1=81=D1=82=D0=B0=D1=80?= =?UTF-8?q?=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit При старте мада (signal_setup) поднимаем мягкий лимит RLIMIT_CORE до жёсткого (обычно unlimited) и логируем итоговый лимит и /proc/sys/kernel/ core_pattern. Зачем: если процесс стартует с маленьким мягким ulimit -c (на проде был 0), ОС пишет урезанный/нулевой core, и в gdb он читается как каша (стек "??") или дампа нет вовсе. Подъём лимита гарантирует полный читаемый core. Лог лимита и core_pattern сразу показывает, пишутся ли коры и куда. Аналог `ulimit -c unlimited` в скрипте запуска, но самодостаточно (не зависит от окружения запуска) и с логированием. Обработчик сигналов и backtrace не трогаются. подключается только для не-Windows сборок. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/engine/core/comm.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/engine/core/comm.cpp b/src/engine/core/comm.cpp index 2d3cf21d7..31d58c14a 100644 --- a/src/engine/core/comm.cpp +++ b/src/engine/core/comm.cpp @@ -67,6 +67,11 @@ #include "engine/db/sqlite_world_data_source.h" #endif #include "utils/utils.h" +#include +#include +#ifndef _WIN32 +#include // RLIMIT_CORE -- только для unix-сборок +#endif #include "engine/core/conf.h" #include "engine/ui/modify.h" #include "gameplay/statistics/money_drop.h" @@ -2261,7 +2266,39 @@ RETSIGTYPE hupsig(int/* sig*/) { * SunOS Release 4.0.2 (sun386) needs this too, according to Tim Aldric. */ +// Поднимаем мягкий лимит на размер core до жёсткого (обычно unlimited), чтобы +// при падении мада ОС писала ПОЛНЫЙ core. Урезанный по размеру core читается в +// gdb как каша (стек неполный, фреймы "??"). Заодно логируем итоговый лимит и +// core_pattern, чтобы было видно, пишутся ли коры и куда. +static void enable_coredumps_and_log() { +#ifdef CIRCLE_UNIX + struct rlimit rl; + if (getrlimit(RLIMIT_CORE, &rl) == 0) { + const rlim_t was = rl.rlim_cur; + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_CORE, &rl) != 0) { + log("SYSERR: setrlimit(RLIMIT_CORE) failed: %s", strerror(errno)); + } + getrlimit(RLIMIT_CORE, &rl); + auto lim = [](rlim_t v) -> long long { return v == RLIM_INFINITY ? -1 : (long long) v; }; + log("Core dumps: RLIMIT_CORE was %lld, set cur=%lld max=%lld (-1 = unlimited)", + lim(was), lim(rl.rlim_cur), lim(rl.rlim_max)); + } else { + log("SYSERR: getrlimit(RLIMIT_CORE) failed: %s", strerror(errno)); + } + if (FILE *f = fopen("/proc/sys/kernel/core_pattern", "r")) { + char pat[256] = {0}; + if (fgets(pat, sizeof(pat), f)) { + pat[strcspn(pat, "\n")] = '\0'; + log("Core pattern: %s", pat); + } + fclose(f); + } +#endif +} + void signal_setup(void) { + enable_coredumps_and_log(); my_signal(SIGINT, hupsig); my_signal(SIGTERM, hupsig); my_signal(SIGPIPE, SIG_IGN);