
Issue #21511 has been updated by luke-gru (Luke Gruber). The fiber is getting freed in the forked process, but it is not the same physical address as the fiber in the parent process. You are seeing virtual addresses here, these processes don't share memory. ---------------------------------------- Bug #21511: Use-after-free of the execution context after the fiber object carrying it is freed in GC https://bugs.ruby-lang.org/issues/21511#change-114082 * Author: tuonigou (tianyang sun) * Status: Open * ruby -v: ruby 3.4.1 (2025-06-13 revision de8de51182) +PRISM [x86_64-linux] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- In bootstraptest/test_thread.rb, ``` ruby assert_equal 'ok', %{ File.write("zzz_t1.rb", <<-END) begin Thread.new { fork { GC.start } }.join pid, status = Process.wait2 $result = status.success? ? :ok : :ng rescue NotImplementedError $result = :ok end END require "./zzz_t1.rb" $result } ``` ``` shell # in build/ make btest BTESTS="file_containing_above.rb" # or ruby --disable=gems "../bootstraptest/runner.rb" --ruby="./miniruby -I../lib -I. -I.ext/common -r./x86_64-linux-fake --disable-gems" file_containing_above.rb ``` Suppose **thread 1** called the `Thread.new` and created **thread 2** The forked process by thread 2 that initiates GC with `GC.start` would sweep the fiber object embedded in `RTypedData` in the `gc_sweep_rest()` stage of sweep in `fiber_free()`. That fiber object contains the execution context of thread 1, `rb_execution_context_t saved_ec` field of `cont`. Since the fiber object is freed, the allocated area pointed by it should be invalid, including the embedded struct for ec, but after thread 2 joins, thread 1 still uses the ec in rb_current_thread(), causing a use after free. -- https://bugs.ruby-lang.org/