Skip to content

Possible deadlock resulting from child receiving signal between TraceExecutor and PerfListener #48

@MikolajKolek

Description

@MikolajKolek

After the parent finishes TraceExecutor::onPostForkParent, every time the child receives a signal, it stops, waiting for for a PTRACE_CONT. This not a problem when PerfListener isn't enabled, as when the parent begins its waitid loop in Executor, it will receive the ptrace notification, and the child will be resumed by TraceExecutor::onExecuteEvent.

However, if PerfListener is enabled, it executes after TraceExecutor. It contains a pthread barrier, which requires the presence of both the parent and the child. If the child receives a signal before either of them reach the barrier, the program will be deadlocked, with the child never receiving the PTRACE_CONT, and the parent never moving past the barrier.

Keep in mind this problem is probably mostly theoretical, as it would require:

  • A non-critical signal to be delivered to the child at all in that timespan, which is almost impossible with normal execution (however can happen, for example with SIGWINCH)
  • The signal needs to hit an extremely precise point in time between TraceExecutor and PerfListener

With that said, I've managed to reproduce it by adding a sleep(1) at the end of TraceExecutor::onPostForkParent and using that time to resize the window and cause a SIGWINCH to be sent to the child, deadlocking the process. I believe this issue can probably be fixed by moving TraceExecutor after PerfListener in the listener order, however I don't know if that won't break anything else.

A similar problem might also theoretically exist in the TraceExecutor, this time not requiring PerfListener. TraceExecutor::onPostForkParent does only one waitpid call, assuming it will receive the exact SIGTRAP sent by the child in TraceExecutor::onPostForkChild. This might theoretically not be correct if it receives a SIGTSTP before the SIGTRAP or finishes with EINTR, but that seems even more unlikely than the previous scenario to me.

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