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 segfault in Ruby 2.6.6 on thread-locals #2567

Merged
merged 1 commit into from Apr 19, 2021
Merged

Handle segfault in Ruby 2.6.6 on thread-locals #2567

merged 1 commit into from Apr 19, 2021

Conversation

kddnewton
Copy link
Contributor

@kddnewton kddnewton commented Mar 8, 2021

When you're trying to access a thread-local variable on Ruby < 2.7, and you call thread_variable_get on a Process::Waiter (a subclass of Thread), it will segfault. This adds a check for which Ruby version you're on to make it safe for Ruby 2.6.

Closes #2566.

Your checklist for this pull request

  • I have reviewed the guidelines for contributing to this repository.
  • I have added an entry to History.md if this PR fixes a bug or adds a feature. If it doesn't need an entry to HISTORY.md, I have added [changelog skip] or [ci skip] to the pull request title.
  • I have added (or updated) appropriate tests if this PR fixes a bug or adds a feature.
  • My pull request is 100 lines added/removed or less so that it can be easily reviewed.
  • If this PR doesn't need tests (docs change), I added [ci skip] to the title of the PR.
  • If this closes any issues, I have added "Closes #issue" to the PR description or my commit messages.
  • I have updated the documentation accordingly.
  • All new and existing tests passed, including Rubocop.

@kddnewton
Copy link
Contributor Author

I'm not entirely sure how to test/document this or if we even need to tbh. Let me know what you think.

@kddnewton
Copy link
Contributor Author

@MSP-Greg tagging you since you commented on the issue

@MSP-Greg
Copy link
Member

MSP-Greg commented Mar 8, 2021

@kddeisz

I'm wondering if thread_variable?(:fork_safe) should be added. The behavior if the variable doesn't exist isn't clearly mentioned in the Ruby docs, it appears that the call is similar to a hash, where nil is returned if the variable/key doesn't exist. That might change?

Since @nateberkopec did the original commit, and I'm not that familiar with "Rails' reaper thread", he should also review.

@nateberkopec
Copy link
Member

So if I understand this correctly, Process::Waiter threads are created by Process.detach.

I think we should clarify if this type of thread is always safe or is always unsafe to exist during fork. It's a pretty simple thread.

@nateberkopec nateberkopec added the waiting-for-review Waiting on review from anyone label Mar 9, 2021
@kddnewton
Copy link
Contributor Author

I think either way the issue is calling thread_variable_get on it for versions < 2.7. Whether or not it is always safe or not is an optimization that is kind of distinct from the bug.

@nateberkopec
Copy link
Member

If we can avoid it, I'd rather avoid the RUBY_VERSION check. So if it's always unsafe or always safe, we can simply exclude it and never need to call thread_local_variable_get on it for any ruby version.

@kddnewton
Copy link
Contributor Author

I think that's fine. I just have no idea how to tell if it's fork safe or not.

@nateberkopec nateberkopec self-assigned this Apr 18, 2021
@nateberkopec
Copy link
Member

OK, so the following needs to be tested:

In a Ruby process, if you Process.detach something (something will live a very long time), and then call fork afterward, that Process::Waiter thread will not be present in the fork, correct?

If true, that is definitely dangerous and could potentially break people's apps (especially in a refork Puma where the master process may get killed).

@kddnewton
Copy link
Contributor Author

@nateberkopec I think that's correct, so the logic should be good now as it includes waiters in the list of non-fork-safe threads. I've updated to remove the ruby version check.

When you're trying to access a thread-local variable on Ruby < 2.7, and you call `thread_variable_get` on a `Process::Waiter` (a subclass of `Thread`), it will segfault. This adds a check for which Ruby version you're on to make it safe for Ruby 2.6.

Fixes #2566.
@nateberkopec
Copy link
Member

Wunderbar!

@nateberkopec nateberkopec merged commit 366496b into puma:master Apr 19, 2021
@kddnewton kddnewton deleted the thread-local-get-on-process-waiter branch April 19, 2021 15:30
JuanitoFatas pushed a commit to JuanitoFatas/puma that referenced this pull request Sep 9, 2022
When you're trying to access a thread-local variable on Ruby < 2.7, and you call `thread_variable_get` on a `Process::Waiter` (a subclass of `Thread`), it will segfault. This adds a check for which Ruby version you're on to make it safe for Ruby 2.6.

Fixes puma#2566.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug waiting-for-review Waiting on review from anyone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Segfault when getting thread-local variable
3 participants