Project

General

Profile

Actions

Bug #21952

open

Ruby::Box double free at process exit when `fiddle/import` is required in multiple boxes

Bug #21952: Ruby::Box double free at process exit when `fiddle/import` is required in multiple boxes

Added by katsyoshi (Katsuyoshi MATSUMOTO) 4 days ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [x86_64-linux]
[ruby-dev:<unknown>]

Description

I found what looks like a separate Ruby::Box bug from the existing require and LoadError issues such as #21760.

This is not a LoadError case. I was able to reduce it to a reproducer where requiring fiddle/import from multiple boxes causes Ruby to abort at process exit with a double free.

Environment:

  • ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [x86_64-linux]
  • Linux x86_64
  • RUBY_BOX=1

Reproducer

Create /tmp/fiddle_require.rb:

require "rubygems"
$:.unshift(*Gem::Specification.find_by_name("fiddle").full_require_paths)
require "fiddle/import"

Then run:

RUBY_BOX=1 ruby -e 'b1 = Ruby::Box.new; b1.require("/tmp/fiddle_require.rb"); b2 = Ruby::Box.new; b2.require("/tmp/fiddle_require.rb")'

Expected behavior

Both Ruby::Box#require calls succeed, and Ruby exits normally.

Actual behavior

Ruby aborts at process exit with:

free(): double free detected in tcache 2
[BUG] Aborted

The C backtrace points into Ruby's Ruby::Box cleanup path, including:

  • free_classext_for_box
  • cleanup_all_local_extensions
  • box_entry_free
  • rb_class_classext_free
  • cvar_table_free_i
  • ruby_sized_xfree

ASAN

I also rebuilt Ruby with AddressSanitizer and reran the same reproducer.

ASAN reports:

  • AddressSanitizer: attempting to call malloc_usable_size() for pointer which is not owned
  • the pointer was originally allocated by rb_cvar_set
  • it was then freed once via cvar_table_free_i
  • and later reached the same cvar_table_free_i cleanup path again through free_classext_for_box and box_entry_free

This makes it look like a class-variable-related allocation created while loading fiddle/import is being freed twice during Ruby::Box cleanup.

Notes

  • I first noticed this while testing fiddle together with shared libraries, but shared library loading is not required for the crash.
  • dlload is not necessary.
  • Reusing the same Ruby module name is not necessary.
  • As a control case, one box requiring fiddle/import and another box requiring a plain Ruby file exits normally.
  • The explicit $: adjustment above is only there to avoid the separate Ruby::Box#require issue where require "fiddle/import" may otherwise fail with LoadError under RUBY_BOX=1.

So this seems to be a separate crash bug in Ruby::Box cleanup triggered by loading fiddle/import in multiple boxes.


Files

asan-sample.txt (13.7 KB) asan-sample.txt AddressSanitizer output for the minimal Ruby::Box + fiddle/import reproducer. katsyoshi (Katsuyoshi MATSUMOTO), 03/12/2026 02:07 PM

No data to display

Actions

Also available in: PDF Atom