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

Ensure the VM is alive before accessing objspace in C API (Feature #19627) #7783

Merged
merged 3 commits into from
May 4, 2023

Conversation

ianks
Copy link
Contributor

@ianks ianks commented May 3, 2023

It is not possible to ensure the Ruby VM is accessible in certain scenarios, such as thread local destructors and async signal handlers.

Previously, it was possible to workaround this by probing the hidden ruby_current_vm_ptr symbol. But as of #7459, those symbols are no longer visible.

To remedy this, this patch adds some null checks when accessing objspace to eliminate known safety issues in the public C API (rb_during_gc, rb_gc and rb_gc_adjust_memory_usage).

prior art: #7663
issue tracker: https://bugs.ruby-lang.org/issues/19627

gc.c Outdated
Comment on lines 1011 to 1014
({ \
rb_vm_t *rb_objspace_ptr_vm = GET_VM(); \
(UNLIKELY(rb_objspace_ptr_vm == NULL)) ? NULL : ((rb_objspace_ptr_vm)->objspace); \
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Statement expression is a gcc extension.

gc.c Outdated
@@ -10914,15 +10919,17 @@ rb_gc_start(void)
void
rb_gc(void)
{
rb_objspace_t *objspace = &rb_objspace;
rb_objspace_t *objspace = rb_objspace_ptr();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than a rb_objspace_ptr macro, wouldn't it be more convenient to implement some kind of EARLY_RETURN_IF_SHUTTING_DOWN kind of help macro?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an idea 😜

#define unless_objspace(objspace) \
    rb_objspace_t *objspace; \
    rb_vm_t *rb_objspace_ptr_vm = GET_VM(); \
    if (rb_objspace_ptr_vm) objspace = rb_objspace_ptr_vm->objspace; \
    else /* return; or objspace will be warned uninitialized */

unless_objspace(objspace) {return;}
// or
unless_objspace(objspace) {return FALSE;}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried out the early return approach, but doing it right involved some do while (0) trickery, and I couldn’t quite get it to properly return default values.

This approach seemed simpler to implement and easier to understand, but happy to try another approach. unless_objspace seems good, I’ll give it a whirl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented in 77ad19c

@ianks ianks requested review from nobu and byroot May 3, 2023 11:50
gc.c Outdated Show resolved Hide resolved
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
@byroot byroot merged commit 2f9f44f into ruby:master May 4, 2023
98 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants