Skip to content

Handle NEWOBJ tracepoints settings fields#15320

Merged
byroot merged 1 commit into
ruby:masterfrom
byroot:struct-newobj-trace-fields
Dec 3, 2025
Merged

Handle NEWOBJ tracepoints settings fields#15320
byroot merged 1 commit into
ruby:masterfrom
byroot:struct-newobj-trace-fields

Conversation

@byroot

@byroot byroot commented Nov 25, 2025

Copy link
Copy Markdown
Member

[Bug #21710]

  • struct.c: struct_alloc

It is possible for a NEWOBJ tracepoint call back to write fields
into a newly allocated object before struct_alloc had the time
to set the RSTRUCT_GEN_FIELDS flags and such.

Hence we can't blindly initialize the fields_obj reference to 0
we first need to check no fields were added yet.

  • object.c: rb_class_allocate_instance

Similarly, if a NEWOBJ tracepoint tries to set fields on the object,
the shape_id must already be set, as it's required on T_OBJECT to
know where to write fields.

NEWOBJ_OF had to be refactored to accept a shape_id.

@cloudbees-smart-tests

cloudbees-smart-tests Bot commented Nov 25, 2025

Copy link
Copy Markdown

1/65368 Tests Failed

test/digest/test_digest.rb#test_race_mixed
Error:
TestDigest::TestDigestParen#test_race_mixed:
Test::Unit::ProxyError: execution of Test::Unit::CoreAssertions#assert_separately expired timeout (10 sec)
pid 74014 exit 0
| 

    /Users/runner/work/ruby/ruby/src/test/digest/test_digest.rb:263:in 'TestDigest::TestDigestParen#test_race_mixed'

[-> View Test suite health in main branch]

@byroot
byroot force-pushed the struct-newobj-trace-fields branch 2 times, most recently from 8500aad to 2e8f36c Compare November 25, 2025 15:09
Comment thread internal/gc.h
Comment on lines +253 to +254
VALUE rb_wb_protected_newobj_of(struct rb_execution_context_struct *, VALUE, VALUE, uint32_t /* shape_id_t */, size_t);
VALUE rb_wb_unprotected_newobj_of(VALUE, VALUE, uint32_t /* shape_id_t */, size_t);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm not proud of this, but I don't think I can include shape.h here, or at least I don't know how to do it.

@byroot
byroot force-pushed the struct-newobj-trace-fields branch from 2e8f36c to 8420853 Compare November 25, 2025 15:14
@byroot byroot changed the title struct_alloc: handle NEWOBJ tracepoints settings fields Handle NEWOBJ tracepoints settings fields Nov 25, 2025
@byroot

byroot commented Nov 25, 2025

Copy link
Copy Markdown
Member Author

The i686 failure looks real, but I have no environment to debug it :/

@byroot

byroot commented Nov 27, 2025

Copy link
Copy Markdown
Member Author

👋 @tenderlove & @jhawthorn would either of you have a bit of time to pair in the near future to figure out the i686 failure? (I still haven't acquired an x86 machine...)

@byroot
byroot force-pushed the struct-newobj-trace-fields branch from 8420853 to 6336ea1 Compare December 2, 2025 21:27
[Bug #21710]

- struct.c: `struct_alloc`

It is possible for a `NEWOBJ` tracepoint call back to write fields
into a newly allocated object before `struct_alloc` had the time
to set the `RSTRUCT_GEN_FIELDS` flags and such.

Hence we can't blindly initialize the `fields_obj` reference to `0`
we first need to check no fields were added yet.

- object.c: `rb_class_allocate_instance`

Similarly, if a `NEWOBJ` tracepoint tries to set fields on the object,
the `shape_id` must already be set, as it's required on T_OBJECT to
know where to write fields.

`NEWOBJ_OF` had to be refactored to accept a `shape_id`.
@byroot
byroot force-pushed the struct-newobj-trace-fields branch from 6336ea1 to ca4bc2b Compare December 2, 2025 22:22
@byroot
byroot enabled auto-merge (rebase) December 3, 2025 07:06
@byroot
byroot merged commit 8c39099 into ruby:master Dec 3, 2025
96 of 98 checks passed
Comment on lines +95 to +98
if (RB_TYPE_P(obj, T_STRING)) {
// Would fail !rb_obj_exivar_p(str) assertion in fstring_concurrent_set_create
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey, I'm curious about this one -- does this mean it's not OK to ask for rb_obj_id from strings? 👀

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Only in DEBUG mode, but to be fair the assertion in question should probably be updated.

Right now it checks !rb_obj_exivar_p which includes the object ID, but it should check that the object doesn't have ivars, object_id is a field, and ivars are fields, but not all fields are ivars.

The naming is a bit confusing too. I'll try to clean that up.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah, perfect, thanks for clarifying! 🙏

@XrXr

XrXr commented Dec 3, 2025

Copy link
Copy Markdown
Member

@byroot

byroot commented Dec 3, 2025

Copy link
Copy Markdown
Member Author

Looking.

@byroot

byroot commented Dec 3, 2025

Copy link
Copy Markdown
Member Author

@XrXr I have a potential fix at #15388 but it's a bit of a stab in the dark. I may have opened a big can of worm here... 😢

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.

3 participants