Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
tesh: rerun the command in valgrind if it segfaults
[simgrid.git] / tools / tesh / tesh.py
index 0d2825f..1a6d8f3 100755 (executable)
@@ -5,7 +5,7 @@
 tesh -- testing shell
 ========================
 
-Copyright (c) 2012-2022. The SimGrid Team. All rights reserved.
+Copyright (c) 2012-2023. The SimGrid Team. All rights reserved.
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the license (GNU LGPL) which comes with this package.
@@ -46,10 +46,6 @@ else:
 #
 #
 
-def is_windows():
-    """ Check if running on Windows """
-    return sys.platform.startswith('win')
-
 # Singleton metaclass that works in Python 2 & 3
 # http://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
 
@@ -120,7 +116,7 @@ def process_is_dead(pid):
 def kill_process_group(pid):
     """ This function send TERM signal + KILL signal after 0.2s to the group of the specified process """
     if pid is None:
-        # Nobody to kill. We don't know who to kill on windows, or we don't have anyone to kill on signal handler
+        # Nobody to kill. We don't have anyone to kill on signal handler
         return
 
     try:
@@ -241,6 +237,7 @@ class Cmd:
         self.output_display = False
 
         self.sort = -1
+        self.rerun_with_valgrind = False
 
         self.ignore_regexps = TeshState().ignore_regexps_common
 
@@ -306,6 +303,12 @@ class Cmd:
             _thread.start_new_thread(Cmd._run, (self, lock))
         else:
             self._run()
+            if self.rerun_with_valgrind:
+                print('\n\n\nXXXXXXXXX Rerunning this test with valgrind to help debugging it XXXXXXXXX')
+                print('(this will fail if valgrind is not installed, of course)\n\n\n')
+
+                self.args = "valgrind " + self.args
+                self._run()
         return True
 
     def _run(self, lock=None):
@@ -356,9 +359,7 @@ class Cmd:
         local_pid = None
 
         try:
-            preexec_function = None
-            if not is_windows():
-                preexec_function = lambda: os.setpgid(0, 0)
+            preexec_function = lambda: os.setpgid(0, 0)
             proc = subprocess.Popen( # pylint: disable=subprocess-popen-preexec-fn
                 args,
                 bufsize=1,
@@ -367,9 +368,8 @@ class Cmd:
                 stderr=subprocess.STDOUT,
                 universal_newlines=True,
                 preexec_fn=preexec_function)
-            if not is_windows():
-                local_pid = proc.pid
-                TeshState().running_pids.append(local_pid)
+            local_pid = proc.pid
+            TeshState().running_pids.append(local_pid)
         except PermissionError:
             logs.append("[{file}:{number}] Cannot start '{cmd}': The binary is not executable.".format(
                 file=FileReader().filename, number=self.linenumber, cmd=args[0]))
@@ -468,6 +468,18 @@ class Cmd:
 
                 logs.append("Test suite `{file}': NOK (<{cmd}> output mismatch)".format(
                     file=FileReader().filename, cmd=cmd_name))
+
+                # Also report any failed return code and/or signal we got in case of output mismatch
+                if not proc.returncode in self.expect_return:
+                    if proc.returncode >= 0:
+                        logs.append("In addition, <{cmd}> returned code {code}.".format(
+                            cmd=cmd_name, code=proc.returncode))
+                    else:
+                        logs.append("In addition, <{cmd}> got signal {sig}.".format(cmd=cmd_name,
+                            sig=SIGNALS_TO_NAMES_DICT[-proc.returncode]))
+                    if proc.returncode == -signal.SIGSEGV:
+                        self.rerun_with_valgrind = True
+
                 if lock is not None:
                     lock.release()
                 if TeshState().keep:
@@ -502,6 +514,10 @@ class Cmd:
             logs.append("Test suite `{file}': NOK (<{cmd}> got signal {sig})".format(
                 file=FileReader().filename, cmd=cmd_name,
                 sig=SIGNALS_TO_NAMES_DICT[-proc.returncode]))
+
+            if proc.returncode == -signal.SIGSEGV:
+                self.rerun_with_valgrind = True
+
             if lock is not None:
                 lock.release()
             TeshState().set_return_code(max(-proc.returncode, 1))
@@ -561,8 +577,6 @@ def main():
             re.compile(r"profiling:"),
             re.compile(r"Unable to clean temporary file C:"),
             re.compile(r".*Configuration change: Set 'contexts/"),
-            re.compile(r"Picked up JAVA_TOOL_OPTIONS: "),
-            re.compile(r"Picked up _JAVA_OPTIONS: "),
             re.compile(r"==[0-9]+== ?WARNING: ASan doesn't fully support"),
             re.compile(r"==[0-9]+== ?WARNING: ASan is ignoring requested __asan_handle_no_return: stack "),
             re.compile(r"False positive error reports may follow"),
@@ -681,7 +695,7 @@ def main():
             cmd.add_ignore(line[len("! ignore "):])
 
         else:
-            fatal_error("UNRECOGNIZED OPTION")
+            fatal_error(f"UNRECOGNIZED OPTION LINE: {line}")
 
         line = file.readfullline()