Class: Audition::Static::NativeExtensions
- Inherits:
-
Object
- Object
- Audition::Static::NativeExtensions
- Defined in:
- lib/audition/static/native_extensions.rb
Overview
Compiled extensions are invisible to the Ruby scanner, but the one fact that decides their Ractor behavior is visible from outside. Ruby marks every method an extension defines while Init_* runs without rb_ext_ractor_safe(true), and calling any of them from a non-main Ractor raises Ractor::UnsafeError. The declaration is a libruby import, so a compiled file names the symbol or does not, whatever language produced it; sources spell it as rb_ext_ractor_safe(true) or the RB_EXT_RACTOR_SAFE(true) macro (C, Rust via rb-sys, Zig).
Compiled files win when present: they are what require
loads. Sources are consulted only for a checkout that has not
been built yet.
Constant Summary collapse
- CHECK =
"native-extension"- SYMBOL =
"rb_ext_ractor_safe"- DECLARATION =
/rb_ext_ractor_safe\s*\(\s*true\s*\)/i- INIT =
/\bInit_\w+\s*\(/- SOURCES =
"*.{c,cc,cpp,cxx,m,mm,h,hpp,rs,zig}"- BUILD_FILES =
%w[Cargo.toml build.zig extconf.rb].freeze
- HARNESS_DIRS =
Harness crates and test trees are not compiled into the extension; a fuzz target that links the VM itself may call rb_ext_ractor_safe without the extension doing so.
%w[fuzz benches tests examples test spec].freeze
- SILENT_WHY =
"Ruby marks every method an extension defines while " \ "Init_* runs without rb_ext_ractor_safe(true), and calling " \ "any of them from a non-main Ractor raises " \ "Ractor::UnsafeError (\"ractor unsafe method called from " \ "not main ractor\"), whether the extension is C, Rust, or " \ "Zig (verified on Ruby 4.0.6). "
- COMPILED_TAIL =
Tails appended to SILENT_WHY at finding time; a constant built with + would hold an unfrozen String.
"The declaration is a libruby import, so a compiled file " \ "that never names the symbol cannot have made it."
- SOURCE_TAIL =
"These sources never call it, so the compiled extension " \ "will raise the same way."
- SILENT_FIX =
"Audit the native code for process-global mutable state " \ "(statics, caches, VALUEs held outside Ruby objects), then " \ "call RB_EXT_RACTOR_SAFE(true) first thing in Init_* " \ "(rb_sys::rb_ext_ractor_safe(true) from Rust). Until then, " \ "keep every call into this extension on the main Ractor."
- DECLARED_WHY =
"rb_ext_ractor_safe(true) is the maintainer's assertion " \ "that the extension keeps no process-global mutable state; " \ "Ruby does not verify it and neither can Audition. Its " \ "methods run from any Ractor, in parallel, on the strength " \ "of that assertion alone."
- DECLARED_FIX =
"Exercise real calls from a non-main Ractor (a script " \ "probe, or the gem's test suite under Ractor.new) before " \ "relying on it."
Instance Method Summary collapse
Instance Method Details
#analyze(target, compiled_files: target.compiled_files) ⇒ Array<Finding>
67 68 69 70 71 72 73 74 75 |
# File 'lib/audition/static/native_extensions.rb', line 67 def analyze(target, compiled_files: target.compiled_files) if compiled_files.any? return compiled_files.filter_map { |p| compiled_finding(p) } end extension_dirs(target.root).map do |dir| source_finding(dir, target.root) end end |