From 733f457882ef5a42137e7da59c26aa9abb207f78 Mon Sep 17 00:00:00 2001 From: prandla Date: Thu, 12 Feb 2026 00:22:37 +0200 Subject: [PATCH] Better handling of compilation memory limit exceeded errors --- cms/grading/Sandbox.py | 12 ++++++++---- cms/grading/steps/compilation.py | 20 +++++++++++++++----- cmstestsuite/Tests.py | 5 +++++ cmstestsuite/code/compile-memory-limit.cpp | 9 +++++++++ 4 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 cmstestsuite/code/compile-memory-limit.cpp diff --git a/cms/grading/Sandbox.py b/cms/grading/Sandbox.py index 7867006902..5066351fda 100644 --- a/cms/grading/Sandbox.py +++ b/cms/grading/Sandbox.py @@ -1289,11 +1289,15 @@ def get_exit_status(self) -> str: return self.EXIT_TIMEOUT_WALL else: return self.EXIT_TIMEOUT + elif 'cg-oom-killed' in self.log: + # OOM killer was activated in the sandbox. It killed either the + # main process (in which case the exit status is SG) or a + # subprocess (in which case the main process gets to decide how to + # handle it, but probably RE). In both cases, we want to + # "root-cause" the verdict as "memory limit exceeded". + return self.EXIT_MEM_LIMIT elif 'SG' in status_list: - if 'cg-oom-killed' in self.log: - return self.EXIT_MEM_LIMIT - else: - return self.EXIT_SIGNAL + return self.EXIT_SIGNAL elif 'RE' in status_list: return self.EXIT_NONZERO_RETURN # OK status is not reported in the log file, it's implicit. diff --git a/cms/grading/steps/compilation.py b/cms/grading/steps/compilation.py index 3b56f2eaad..443fd49cbc 100644 --- a/cms/grading/steps/compilation.py +++ b/cms/grading/steps/compilation.py @@ -55,13 +55,16 @@ def N_(message: str): N_("Your submission exceeded the time limit while compiling. " "This might be caused by an excessive use of C++ " "templates, for example.")), + HumanMessage("memorylimit", + N_("Compilation memory limit exceeded"), + N_("Your submission exceeded the memory limit while compiling. " + "This might be caused by an excessive use of C++ " + "templates, or too large global variables, for example.")), HumanMessage("signal", - N_("Compilation killed with signal %s (could be triggered " - "by violating memory limits)"), + N_("Compilation killed with signal %s"), N_("Your submission was killed with the specified signal. " - "Among other things, this might be caused by exceeding " - "the memory limit for the compilation, and in turn by an " - "excessive use of C++ templates, for example.")), + "This might be caused by a bug in the compiler, " + "for example.")), ]) @@ -136,6 +139,13 @@ def compilation_step( text = [COMPILATION_MESSAGES.get("timeout").message] return True, False, text, stats + elif exit_status == Sandbox.EXIT_MEM_LIMIT: + # Memory limit: we assume it is the user's fault, and we return the + # error to them. + logger.debug("Compilation memory limit exceeded.") + text = [COMPILATION_MESSAGES.get("memorylimit").message] + return True, False, text, stats + elif exit_status == Sandbox.EXIT_SIGNAL: # Terminated by signal: we assume again it is the user's fault, and # we return the error to them. diff --git a/cmstestsuite/Tests.py b/cmstestsuite/Tests.py index 03870f6d49..67baea705f 100644 --- a/cmstestsuite/Tests.py +++ b/cmstestsuite/Tests.py @@ -196,6 +196,11 @@ languages=(LANG_CPP,), checks=[CheckCompilationFail()]), + Test('compile-memory-limit', + task=batch_fileio, filenames=['compile-memory-limit.%l'], + languages=(LANG_CPP,), + checks=[CheckCompilationFail()]), + # Various timeout conditions. Test('timeout-cputime', diff --git a/cmstestsuite/code/compile-memory-limit.cpp b/cmstestsuite/code/compile-memory-limit.cpp new file mode 100644 index 0000000000..4548845394 --- /dev/null +++ b/cmstestsuite/code/compile-memory-limit.cpp @@ -0,0 +1,9 @@ +#ifdef EVAL // this file can accidentally OOM editors/language servers... +#define a "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +#define b a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a +#define c b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b +#define d c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c +#define e d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d +const char* x = e e; +#endif +int main() { return 0; }