diff options
author | 2020-11-20 23:46:19 +0100 | |
---|---|---|
committer | 2020-11-20 23:47:18 +0100 | |
commit | 162e669032f377e0ba3751ed5a924c84789696d8 (patch) | |
tree | c6bdeaa6df8fc76bc95f21973a1cf44a261f2d48 | |
parent | Document output truncation in README (diff) |
Convert negative exit codes into standard form
When you send a signal `N` to a subprocess using Popen, it will return
`-N` as its exit code. As the rest of the code returns signal exit codes
as `128 + N`, we convert those negative exit codes into the standard
form used by the rest of the code.
-rw-r--r-- | snekbox/nsjail.py | 22 | ||||
-rw-r--r-- | tests/test_nsjail.py | 2 |
2 files changed, 15 insertions, 9 deletions
diff --git a/snekbox/nsjail.py b/snekbox/nsjail.py index 6fc0343..8edf546 100644 --- a/snekbox/nsjail.py +++ b/snekbox/nsjail.py @@ -7,7 +7,7 @@ import textwrap from pathlib import Path from subprocess import CompletedProcess from tempfile import NamedTemporaryFile -from typing import Iterable +from typing import Iterable, Tuple from snekbox import DEBUG @@ -105,7 +105,7 @@ class NsJail: log.error(msg) @staticmethod - def _consume_stdout(nsjail: subprocess.Popen) -> str: + def _consume_stdout(nsjail: subprocess.Popen) -> Tuple[int, str]: """ Consume STDOUT, stopping when the output limit is reached or NsJail has exited. @@ -115,7 +115,7 @@ class NsJail: is asked to terminate with a SIGKILL. Once the subprocess has exited, either naturally or because it was terminated, - the output up to that point is returned as a string. + we return the exit code as an int and the output as a single string. """ output_size = 0 output = [] @@ -128,13 +128,19 @@ class NsJail: if output_size > OUTPUT_MAX: # Terminate the NsJail subprocess with SIGKILL. + log.info(f"Output exceeded the output limit, sending SIGKILL to NsJail.") nsjail.kill() break # Ensure that we wait for the NsJail subprocess to terminate. nsjail.wait() - return "".join(output) + # When you send signal `N` to a subprocess to terminate it using Popen, it + # will return `-N` as its exit code. As we normally get `N + 128` back, we + # convert negative exit codes to the `N + 128` form. + returncode = -nsjail.returncode + 128 if nsjail.returncode < 0 else nsjail.returncode + + return returncode, "".join(output) def python3(self, code: str) -> CompletedProcess: """Execute Python 3 code in an isolated environment and return the completed process.""" @@ -168,14 +174,14 @@ class NsJail: except ValueError: return CompletedProcess(args, None, "ValueError: embedded null byte", None) - output = self._consume_stdout(nsjail) + returncode, output = self._consume_stdout(nsjail) log_lines = nsj_log.read().decode("utf-8").splitlines() - if not log_lines and nsjail.returncode == 255: + if not log_lines and returncode == 255: # NsJail probably failed to parse arguments so log output will still be in stdout log_lines = output.splitlines() self._parse_log(log_lines) - log.info(f"nsjail return code: {nsjail.returncode}") - return CompletedProcess(args, nsjail.returncode, output, None) + log.info(f"nsjail return code: {returncode}") + return CompletedProcess(args, returncode, output, None) diff --git a/tests/test_nsjail.py b/tests/test_nsjail.py index 4a040e7..691eb5b 100644 --- a/tests/test_nsjail.py +++ b/tests/test_nsjail.py @@ -182,4 +182,4 @@ class NsJailTests(unittest.TestCase): """).strip() result = self.nsjail.python3(stdout_flood) - self.assertEqual(result.returncode, -9) + self.assertEqual(result.returncode, 137) |