Project

General

Profile

Actions

Bug #21710

open

Segfault when reading object_id after it is set inside RUBY_INTERNAL_EVENT_NEWOBJ

Bug #21710: Segfault when reading object_id after it is set inside RUBY_INTERNAL_EVENT_NEWOBJ

Added by ivoanjo (Ivo Anjo) about 13 hours ago. Updated about 8 hours ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.0.0dev (2025-11-24T08:44:28Z master aeb7689e69) +PRISM [x86_64-linux]
[ruby-core:123902]

Description

Hey 👋. I caught a following segfault when running the Datadog Ruby Profiler test suite on 4.0.0-preview2.

The Datadog Ruby Profiler still uses object_ids in RUBY_INTERNAL_EVENT_NEWOBJ to simulate weak references. (We know this is deprecated and we plan to move to rb_gc_mark_weak in the future).

I was able to reproduce this bug with both 4.0.0-preview2 as well as a ruby-head build from 2025-11-24.

Here's a very simple reproducer:

static void on_newobj_event(VALUE tpval, void *data) {
  VALUE obj = rb_tracearg_object(rb_tracearg_from_tracepoint(tpval));
  if (!rb_objspace_internal_object_p(obj)) rb_obj_id(obj);
}

static VALUE add_object_id(RB_UNUSED_VAR(VALUE _)) {
  VALUE tp = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, on_newobj_event, NULL);
  rb_tracepoint_enable(tp); rb_yield(Qnil); rb_tracepoint_disable(tp);
  return Qnil;
}
puts RUBY_DESCRIPTION

require "lowlevel-toolkit"

foo = Struct.new(:foo)
bar = nil
LowlevelToolkit.add_object_id { bar = foo.new(1) }
bar.object_id

and here's the segfault:

examples/add_object_id.rb:8: [BUG] Segmentation fault at 0x0000000000000000
ruby 4.0.0dev (2025-11-24T08:44:28Z master aeb7689e69) +PRISM [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0003 p:---- s:0012 e:000011 l:y b:---- CFUNC  :object_id
c:0002 p:0044 s:0008 E:002170 l:n b:---- EVAL   examples/add_object_id.rb:8 [FINISH]
c:0001 p:0000 s:0003 E:001dc0 l:y b:---- DUMMY  [FINISH]

-- Ruby level backtrace information ----------------------------------------
examples/add_object_id.rb:8:in '<main>'
examples/add_object_id.rb:8:in 'object_id'

-- Threading information ---------------------------------------------------
Total ractor count: 1
Ruby thread count for this ractor: 1

-- Machine register context ------------------------------------------------
 RIP: 0x000079c33b33e2cd RBP: 0x00007ffdcee65d10 RSP: 0x00007ffdcee65cd0
 RAX: 0x0000000000000000 RBX: 0x000079c33a4ff058 RCX: 0x000079c339000000
 RDX: 0x0000000000000000 RDI: 0x0000000000000000 RSI: 0x00000000000fe000
  R8: 0x000079c33b35c078  R9: 0x000079c31f2814d0 R10: 0x000058e4893a6ee0
 R11: 0xb84a1fbe2b4aab11 R12: 0x0000000000000002 R13: 0x0000000000000000
 R14: 0x000058e489384b60 R15: 0x000079c33a5fefa0 EFL: 0x0000000000010246

-- C level backtrace information -------------------------------------------
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_print_backtrace+0x24) [0x79c33b392149] .rvm/src/ruby-head/vm_dump.c:1105
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_vm_bugreport+0x33f) [0x79c33b39291b] .rvm/src/ruby-head/vm_dump.c:1450
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_bug_for_fatal_signal+0x147) [0x79c33b13a3e2]
.rvm/rubies/ruby-head/lib/libruby.so.4.0(sigsegv+0x84) [0x79c33b2bea4d] .rvm/src/ruby-head/signal.c:948
.rvm/rubies/ruby-head/lib/libruby.so.4.0(sigill) (null):0
/lib/x86_64-linux-gnu/libc.so.6(0x79c33ac45330) [0x79c33ac45330]
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_obj_field_get+0x105) [0x79c33b33e2cd] .rvm/src/ruby-head/variable.c:1412
.rvm/rubies/ruby-head/lib/libruby.so.4.0(object_id_get+0x4e) [0x79c33b16ed28] .rvm/src/ruby-head/gc.c:1875
.rvm/rubies/ruby-head/lib/libruby.so.4.0(object_id0+0x46) [0x79c33b16ed78] .rvm/src/ruby-head/gc.c:1895
.rvm/rubies/ruby-head/lib/libruby.so.4.0(object_id+0xb1) [0x79c33b16ee93] .rvm/src/ruby-head/gc.c:1936
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_find_object_id+0x43) [0x79c33b16f6ea] .rvm/src/ruby-head/gc.c:2179
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_obj_id+0x2e) [0x79c33b16f75a] .rvm/src/ruby-head/gc.c:2234
.rvm/rubies/ruby-head/lib/libruby.so.4.0(ractor_safe_call_cfunc_0+0x30) [0x79c33b35c0a8] .rvm/src/ruby-head/vm_insnhelper.c:3718
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_call_cfunc_with_frame_+0x221) [0x79c33b35ccb1] .rvm/src/ruby-head/vm_insnhelper.c:3902
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_call_cfunc_with_frame+0x76) [0x79c33b35cf26] .rvm/src/ruby-head/vm_insnhelper.c:3948
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_call_cfunc_other+0x12b) [0x79c33b35d053] .rvm/src/ruby-head/vm_insnhelper.c:3974
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_call_cfunc+0x147) [0x79c33b35d49a] .rvm/src/ruby-head/vm_insnhelper.c:4056
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_call_method_each_type+0x180) [0x79c33b360161] .rvm/src/ruby-head/vm_insnhelper.c:4888
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_call_method+0xa1) [0x79c33b360c1d] .rvm/src/ruby-head/vm_insnhelper.c:5014
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_call_general+0x2f) [0x79c33b360e1f] .rvm/src/ruby-head/vm_insnhelper.c:5058
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_sendish+0x1d3) [0x79c33b363689] .rvm/src/ruby-head/vm_insnhelper.c:6124
.rvm/rubies/ruby-head/lib/libruby.so.4.0(vm_exec_core+0x3b1d) [0x79c33b36b42c] .rvm/src/ruby-head/insns.def:903
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_vm_exec+0x140) [0x79c33b384d94] .rvm/src/ruby-head/vm.c:2784
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_iseq_eval_main+0x3d) [0x79c33b385be2] .rvm/src/ruby-head/vm.c:3050
.rvm/rubies/ruby-head/lib/libruby.so.4.0(rb_ec_exec_node+0x128) [0x79c33b145eb4] .rvm/src/ruby-head/eval.c:283
.rvm/rubies/ruby-head/lib/libruby.so.4.0(ruby_run_node+0x8a) [0x79c33b146025] .rvm/src/ruby-head/eval.c:321
.rvm/rubies/ruby-head/bin/ruby(rb_main+0x4c) [0x58e47500e51e] ./main.c:42
.rvm/rubies/ruby-head/bin/ruby(main+0x62) [0x58e47500e596] ./main.c:62

Let me know if I can provide any more info!


Files

bug-21710.patch (1.25 KB) bug-21710.patch nobu (Nobuyoshi Nakada), 11/25/2025 02:19 PM

Updated by byroot (Jean Boussier) about 10 hours ago Actions #1 [ruby-core:123904]

I believe I understand what's going on. The NEWOBJ callback is invoked before struct_alloc has set the necessary flags such as RSTRUCT_GEN_FIELDS and RSTRUCT_EMBED_LEN_MASK.

This cause rb_object_id to look for, and set, the fields_obj at the wrong place.

The ideal fix would be for struct_alloc to invoke NEWOBJ_OF with all these flags, instead of setting them later. Not 100% sure it's possible though, but I'll keep digging.

Updated by byroot (Jean Boussier) about 9 hours ago Actions #2 [ruby-core:123905]

  • Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN to 3.2: DONTNEED, 3.3: DONTNEED, 3.4: DONTNEED

I got a fix here: https://github.com/ruby/ruby/pull/15320

But I'd like to find some time to add a regression test, or at the very least to audit the other types to see if a similar issue is possible with the other types that also optimize generic fields access (e.g. T_DATA).

Updated by nobu (Nobuyoshi Nakada) about 9 hours ago Actions #3 [ruby-core:123906]

With the attached patch, GH-15320 works fine for Struct.

$ ./ruby -r-test-/tracepoint -e 'foo = Struct.new(:foo); bar = nil; Bug.tracepoint_add_object_id { bar = foo.new(1) }; p bar.object_id'
16

Crashes for Object.

$ ./ruby -r-test-/tracepoint -e 'bar = nil; Bug.tracepoint_add_object_id { bar = Object.new }; p bar.object_id'
../src/shape.c:1295: Assertion Failed: rb_shape_verify_consistency:flags_heap_index > 0
ruby 4.0.0dev (2025-11-25T14:15:17Z master 24268ceb68) +PRISM [arm64-darwin25]

C level backtrace is:

/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_vm_bugreport+0xbd8) [0x101726c8c] /Users/nobu/build/ruby/master/aarch64-darwin/../src/vm_dump.c:1450
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_vm_bugreport) (null):0
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_assert_failure_detail+0xd4) [0x101894e28] /Users/nobu/build/ruby/master/aarch64-darwin/../src/error.c:1216
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_assert_failure_detail+0x0) [0x101894d54] /Users/nobu/build/ruby/master/aarch64-darwin/../src/error.c:1192
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_assert_failure) (null):0
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_shape_verify_consistency.cold.8+0x0) [0x1018ba9a0] /Users/nobu/build/ruby/master/aarch64-darwin/../src/shape.c:1295
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_shape_verify_consistency.cold.7) (null):0
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_shape_verify_consistency+0x154) [0x101668428] /Users/nobu/build/ruby/master/aarch64-darwin/../src/shape.c:1295
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(obj_field_set+0xec) [0x1016e3c98] ../src/shape.h:177
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(RB_BUILTIN_TYPE+0x0) [0x10155f91c] /Users/nobu/build/ruby/master/aarch64-darwin/../src/gc.c:1901
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rbimpl_RB_TYPE_P_fastpath) ../src/include/ruby/internal/value_type.h:352
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(object_id0) ../src/shape.h:145
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(exec_hooks_body+0x20) [0x101728dc0] /Users/nobu/build/ruby/master/aarch64-darwin/../src/vm_trace.c:358
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(exec_hooks_unprotected) /Users/nobu/build/ruby/master/aarch64-darwin/../src/vm_trace.c:387
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_exec_event_hooks+0xc8) [0x101728d04] /Users/nobu/build/ruby/master/aarch64-darwin/../src/vm_trace.c:433
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_exec_event_hook_orig+0x58) [0x10155f2d0] ../src/vm_core.h:2293
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_gc_event_hook+0x30) [0x101555d3c] /Users/nobu/build/ruby/master/aarch64-darwin/../src/gc.c:237
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(newobj_of.cold.6+0x5c) [0x101898cb8] /Users/nobu/build/ruby/master/aarch64-darwin/../src/gc.c:1012
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(newobj_of+0x258) [0x10154be38] /Users/nobu/build/ruby/master/aarch64-darwin/../src/gc.c:1001
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(RB_SPECIAL_CONST_P+0x0) [0x1015c7ebc] /Users/nobu/build/ruby/master/aarch64-darwin/../src/object.c:127
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_class_allocate_instance) ../src/shape.h:144
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_class_alloc+0x68) [0x1015c9d40] /Users/nobu/build/ruby/master/aarch64-darwin/../src/object.c:2214
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(vm_exec_core+0xf50) [0x1016f28f8] /Users/nobu/build/ruby/master/aarch64-darwin/insns.def:928
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_vm_exec+0x170) [0x1016efce8] /Users/nobu/build/ruby/master/aarch64-darwin/../src/vm.c:2784
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(invoke_block_from_c_bh+0x2f4) [0x10171ed48] /Users/nobu/build/ruby/master/aarch64-darwin/../src/vm.c:1814
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_yield_0+0x80) [0x101700e9c] /Users/nobu/build/ruby/master/aarch64-darwin/../src/vm.c:1865
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_yield+0x60) [0x101700f2c] ../src/vm_eval.c:1378
/Users/nobu/build/ruby/master/aarch64-darwin/.ext/arm64-darwin25/-test-/tracepoint.bundle(add_object_id+0x34) [0x1008e0afc] /Users/nobu/build/ruby/master/aarch64-darwin/ext/-test-/tracepoint/../../../../src/ext/-test-/tracepoint/tracepoint.c:103
/Users/nobu/build/ruby/master/aarch64-darwin/.ext/arm64-darwin25/-test-/tracepoint.bundle(add_object_id) (null):0
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(vm_call_cfunc_with_frame_+0xe8) [0x1017155d0] ../src/vm_insnhelper.c:3902
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(vm_sendish+0x6fc) [0x1016ef9cc]
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(vm_exec_core+0xb70) [0x1016f2518]
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_vm_exec+0x170) [0x1016efce8] /Users/nobu/build/ruby/master/aarch64-darwin/../src/vm.c:2784
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(rb_ec_exec_node+0x74) [0x101539908] /Users/nobu/build/ruby/master/aarch64-darwin/../src/eval.c:283
/Users/nobu/build/ruby/master/aarch64-darwin/libruby.4.0.dylib(ruby_run_node+0x64) [0x101539838] /Users/nobu/build/ruby/master/aarch64-darwin/../src/eval.c:321
/Users/nobu/build/ruby/master/aarch64-darwin/ruby(rb_main+0x1c) [0x100828600] /Users/nobu/build/ruby/master/aarch64-darwin/../src/main.c:42
/Users/nobu/build/ruby/master/aarch64-darwin/ruby(main) /Users/nobu/build/ruby/master/aarch64-darwin/../src/main.c:62
/Users/nobu/build/ruby/master/aarch64-darwin/ruby(main) (null):0

Updated by byroot (Jean Boussier) about 9 hours ago Actions #4 [ruby-core:123907]

Thank you @nobu (Nobuyoshi Nakada), I'll integrate your test case and fix the remaining issues.

Updated by byroot (Jean Boussier) about 8 hours ago Actions #5 [ruby-core:123908]

I'm still waiting on CI, but https://github.com/ruby/ruby/pull/15320 now handles T_OBJECT too and include @nobu's test. Review welcome.

Actions

Also available in: PDF Atom