Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle execve's on Linux #177

Merged
merged 4 commits into from May 20, 2019
Merged

Handle execve's on Linux #177

merged 4 commits into from May 20, 2019

Conversation

wabain
Copy link
Contributor

@wabain wabain commented Sep 4, 2018

This is a fix for #145, handling exec calls, for Linux. While the same approach should work for MacOS, extra work would be needed to distinguish between invalid reads and process exit and since I've already let this sit for many months, I'd prefer to land Linux support.

The idea here is to check the result returned when getting the stack trace from the target process to detect the error that the pointer to the ruby thread state, specifically, has become invalid. If it has, we then reinitialize StackTraceGetter on the basis that if we've lost the thread the whole process is invalid.

In the test case I added I'm polling until the reinitialization happens. I did this because when I used a fixed timeout I was sometimes getting the trace before reinitialization (one every 500 test runs or so), and I didn't want to play the timeout tweaking game. With the current polling I still get the error "stack base and cfp address out of sync" once every few thousand test runs but I think that error should be transient and shouldn't impact real usage.

When an execve is executed, the process's memory is replaced with the memory
of a new program. When the new program is also a Ruby interpreter instance,
rbspy should continue to gather stack traces. This is particularly important
because some Ruby invocation methods, such as rvm, may do an execve to launch
the script being invoked by the user.

The strategy here is to check the result returned when getting the stack trace
from the target process to detect the error that the pointer into the ruby
thread state, specifically, has become invalid. If it has, we then reinitialize
StackTraceGetter on the basis that if we've lost our thread the whole process
is invalid.

Currently this doesn't work on MacOS because the error-handling for copying
addresses can't distinguish between an invalid read and process exit.
Fixing that would require either changing the interface of
read-process-memory to surface the mach return codes or just working around
it in rbspy.

It might also not work as reliably on 32-bit platforms, where there may be
a greater chance of the thread state pointer being remapped into the
memory of the new process.
Make StackTraceGetter take ProcessHandle instead of a generic,
since doing anything meaningful with StackTraceGetter now requires
it to support reinitialization. Add a type alias for the boxed
stack trace type.
@wabain wabain changed the title WIP: Handle execve's Handle execve's on Linux Feb 9, 2019
@daniellockyer
Copy link
Collaborator

Looks good to me and appears to fix #145 👍

@daniellockyer daniellockyer merged commit 806ace5 into rbspy:master May 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants