From 0db2e1e91a9124c276fd00f674b71f038a53ddec Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 18 Mar 2024 09:17:46 -0700 Subject: Reland "[compiler-rt] Avoid generating coredumps when piped to a tool" Updated the corelimit.cpp test to handle buildbots with RLIMIT_CORE rlim_max already set to zero. Original commit message: I was trying to debug why `ninja check-compiler-rt` was taking so long to run on my system and after some debugging it turned out that most of the time was being spent generating core dumps. On many current Linux systems, coredumps are no longer dumped in the CWD but instead piped to a utility such as systemd-coredumpd that stores them in a deterministic location. This can be done by setting the kernel.core_pattern sysctl to start with a '|'. However, when using such a setup the kernel ignores a coredump limit of 0 (since there is no file being written) and we can end up piping many gigabytes of data to systemd-coredumpd which causes the test suite to freeze for a long time. While most piped coredump handlers do respect the crashing processes' RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump due to a local patch that changes sysctl.d/50-coredump.conf to ignore the specified limit and instead use RLIM_INFINITY (https://salsa.debian.org/systemd-team/systemd/-/commit/64599ffe44f0d). Fortunately there is a workaround: the kernel recognizes the magic value of 1 for RLIMIT_CORE to disable coredumps when piping. One byte is also too small to generate any coredump, so it effectively behaves as if we had set the value to zero. The alternative to using RLIMIT_CORE=1 would be to use prctl() with the PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it impossible to attach a debugger. Fixes: https://github.com/llvm/llvm-project/issues/45797 This reverts commit 0b9f19a9880eb786871194af116f223d2ad30c52. --- .../sanitizer_common/sanitizer_posix_libcdep.cpp | 22 +++++++++++++++++++++- .../test/sanitizer_common/TestCases/corelimit.cpp | 4 +++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index ef1fc35..ece2d7d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -104,7 +104,27 @@ static void setlim(int res, rlim_t lim) { void DisableCoreDumperIfNecessary() { if (common_flags()->disable_coredump) { - setlim(RLIMIT_CORE, 0); + rlimit rlim; + CHECK_EQ(0, getrlimit(RLIMIT_CORE, &rlim)); + // On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it + // is being piped to a coredump handler such as systemd-coredumpd), the + // kernel ignores RLIMIT_CORE (since we aren't creating a file in the file + // system) except for the magic value of 1, which disables coredumps when + // piping. 1 byte is too small for any kind of valid core dump, so it + // also disables coredumps if kernel.core_pattern creates files directly. + // While most piped coredump handlers do respect the crashing processes' + // RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump + // due to a local patch that changes sysctl.d/50-coredump.conf to ignore + // the specified limit and instead use RLIM_INFINITY. + // + // The alternative to using RLIMIT_CORE=1 would be to use prctl() with the + // PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it + // impossible to attach a debugger. + // + // Note: we use rlim_max in the Min() call here since that is the upper + // limit for what can be set without getting an EINVAL error. + rlim.rlim_cur = Min(SANITIZER_LINUX ? 1 : 0, rlim.rlim_max); + CHECK_EQ(0, setrlimit(RLIMIT_CORE, &rlim)); } } diff --git a/compiler-rt/test/sanitizer_common/TestCases/corelimit.cpp b/compiler-rt/test/sanitizer_common/TestCases/corelimit.cpp index 2378a4cf..9b56471 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/corelimit.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/corelimit.cpp @@ -10,7 +10,9 @@ int main() { getrlimit(RLIMIT_CORE, &lim_core); void *p; if (sizeof(p) == 8) { - assert(0 == lim_core.rlim_cur); + // rlim_cur will be set to zero or one depending on the target OS and + // initial core limits. See comments in DisableCoreDumperIfNecessary(). + assert(lim_core.rlim_cur <= 1u); } return 0; } -- cgit v1.1