Skip to content

runtests: Tests can pass while rtapi_app crashes #4707

Open

Description

@hdiethelm

Discovered while searching for issues in: #4669

Steps to reproduce:

  1. Trigger a segfault at rtapi_app exit
diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc
index 9946f3d16d..8dcf213e36 100644
--- a/src/rtapi/uspace_rtapi_main.cc
+++ b/src/rtapi/uspace_rtapi_main.cc
@@ -1003,6 +1003,7 @@ static int handle_command(const std::vector<std::string> &args, std::string &out
         return 0;
     } else if (args.size() == 1 && args[0] == "exit") {
         force_exit = 1;
+        *(volatile int *)0 = 0; //Trigger a segfault at exit
         return 0;
     } else if (args.size() >= 2 && args[0] == "load") {
         std::string name = args[1];
  1. Run a test
scripts/runtests tests/abs.0
Running test: tests/abs.0
Runtest: 1 tests run, 1 successful, 0 failed, 0 skipped, 0 shmem errors
  1. dmesg: There was a segfault during the test but it passed. I would expect the test to fail.

An idea to solve this was discussed in #4703 (comment)

#4648 should be merged before starting this to avoid merge conflicts.

Activity

  1. BsAtHome commented on Oct 21, 2026

    @BsAtHome
    Contributor

    This is the slave rtapi_app or the master when at the exit point, I guess. While it is problematic that the test succeeds with a crashed rtapi_app, the actual test did succeed.

    Just like the shmem test added to runtests, we should check for segfaults/code dumps after each test and fail accordingly.

  2. grandixximo commented on Oct 26, 2026

    @grandixximo
    Contributor

    @hdiethelm #4648 merged, are you taking this on?

  3. hdiethelm commented on Oct 26, 2026

    @hdiethelm
    ContributorAuthor
    1. This is the slave rtapi_app or the master when at the exit point, I guess. While it is problematic that the test succeeds with a crashed rtapi_app, the actual test did succeed.
      Just like the shmem test added to runtests, we should check for segfaults/code dumps after each test and fail accordingly.

    Exactly, this was the idea. They might also be other processes crashing and if there are no side effects, no one will notice.

    @grandixximo Before taking this on, I wanted to spend some time in improving the real time doc and add a few tools to simplify configuration. If you would like to take this on, feel free. Just tag me so we don't do it at the same time... ;-)

  4. grandixximo commented on Oct 28, 2026

    @grandixximo
    Contributor

    @hdiethelm I won't take this on, but I ran your repro in a few configurations, in case the results save you time.

    Setup: master 07aa2ba, stock Debian 6.12 kernel, crash patch from the issue, runtests tests/abs.0 in private ipc/pid/net namespaces, ulimit -c unlimited, core_pattern=core. abs.0 passed in every run.

    rtapi_app rtapi_app: SIGSEGV - aborting in stderr core, suid_dumpable=0 / 2
    plain, POSIX non-realtime no yes / yes
    setcap, LINUXCNC_FORCE_REALTIME=1 yes yes / yes
    setuid, LINUXCNC_FORCE_REALTIME=1 yes no / no
    • rtapi_app: failed to read from master was in the test's stderr in every run (the slave waiting for the exit reply).
    • The signal handler is only installed in harden_rt(), which only runs for a realtime type, so in POSIX mode (CI, most runtests runs) nothing is printed.
    • setuid: the prctl(PR_SET_DUMPABLE, 1) does not survive. With suid_dumpable=2 the kernel logs rtapi_app: this process can only dump core to a fully qualified path, skipping core dump, so the flag was reset; prctl(2) says any fsuid change does that, and WithRoot calls setfsuid(). With setcap there is no fsuid change and the core is written.
    • Once the handler is installed, the kernel no longer logs segfault at ... (only the POSIX runs did), and dmesg needs CAP_SYSLOG anyway.
    • Without raising the limit, Debian's default soft core 0 meant no core at all in POSIX mode.

    So a journal/coredump scan would miss the setuid case and depends on systemd, while the stderr lines are there regardless of distro, privileges or sandbox.

    For reference, other projects mostly fail a test when a process it started dies from a signal (PostgreSQL, piglit, QEMU iotests, GLib, Wine, LTP); systemd scans coredumpctl but owns the whole VM. For a daemon that is not a child of the runner, prctl(PR_SET_CHILD_SUBREAPER, 1) (as tini -s does) re-parents it to the runner so waitpid() sees the signal; that needs a small C or Python helper since bash cannot set it.

    Your call how to proceed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions