-
-
Notifications
You must be signed in to change notification settings - Fork 760
Labels
pending triageThe issue/PR is currently untouched.The issue/PR is currently untouched.
Description
System Info
- Rspack/Rsbuild version: 1.6.6
- swc-loader version: 0.2.7
- @swc/core version: 1.14.0
- Node.js version: 18.20.8
- OS: macOS (Apple Silicon / arm64)
Details
Summary
When using swc-loader (npm package) instead of builtin:swc-loader with Rspack, a race condition causes memory crashes (SIGBUS/SIGSEGV) due to a use-after-free issue in BuildInfo::with_ref.
Steps to reproduce
- Replace
builtin:swc-loaderwithswc-loader(npm package) in bundlerChain:
// rsbuild.config.ts
bundlerChain: (chain, { CHAIN_ID }) => {
const jsRule = chain.module.rule(CHAIN_ID.RULE.JS)
jsRule
.use('swc')
.loader('swc-loader') // npm package instead of builtin:swc-loader
.options({
jsc: {
target: 'es2016',
parser: { tsx: true, syntax: 'typescript' },
experimental: {
plugins: [
['@swc/plugin-styled-components', { /* ... */ }],
]
},
}
})
}- Run
rsbuild devwith a large project (many files) - The build crashes with ~90% probability
Error message
Panic occurred at runtime. Please file an issue on GitHub with the backtrace below:
https://github.com/web-infra-dev/rspack/issues:
panicked at /rustc/.../library/alloc/src/raw_vec/mod.rs:558:17:
capacity overflow
Or:
memory allocation of 25457679912665952 bytes failed
Workaround
Adding a passthrough loader with an empty pitch function before swc-loader prevents the crash:
// pitch-workaround.js
module.exports = function passthroughLoader(source) {
return source
}
module.exports.pitch = function () {
// Empty - just needs to exist
}jsRule
.use('pitch-workaround')
.loader('./pitch-workaround.js')
.end()
.use('swc')
.loader('swc-loader')
.options(swcOptions)Root Cause Analysis
Debug stack trace (using @rspack-debug/core@1.6.6)
Crash 1: SIGBUS
Process 6938 stopped
* thread #1, name = 'rsbuild-node', queue = 'com.apple.main-thread', stop reason = signal SIGBUS
frame #0: 0x00000001130c584c rspack.darwin-arm64.node`<rspack_binding_api::build_info::BuildInfo>::with_ref::<(), <rspack_binding_api::build_info::BuildInfo as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value::{closure#0}::{closure#1}> + 120
rspack.darwin-arm64.node`<rspack_binding_api::build_info::BuildInfo>::with_ref::<(), <rspack_binding_api::build_info::BuildInfo as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value::{closure#0}::{closure#1}>:
-> 0x1130c584c <+120>: ldr x8, [x0, #0x48]
0x1130c5850 <+124>: cmn x8, #0x1
0x1130c5854 <+128>: b.eq 0x1130c5c24 ; <+1104>
0x1130c5858 <+132>: mov x22, x0
Target 0: (node) stopped.
(lldb) bt
* thread #1, name = 'rsbuild-node', queue = 'com.apple.main-thread', stop reason = signal SIGBUS
* frame #0: 0x00000001130c584c rspack.darwin-arm64.node`<rspack_binding_api::build_info::BuildInfo>::with_ref::<(), <rspack_binding_api::build_info::BuildInfo as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value::{closure#0}::{closure#1}> + 120
frame #1: 0x0000000112f9b144 rspack.darwin-arm64.node`<std::thread::local::LocalKey<core::cell::RefCell<alloc::vec::Vec<napi::js_values::object_property::Property>>>>::with::<<rspack_binding_api::build_info::BuildInfo as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value::{closure#0}, core::result::Result<(), napi::error::Error>> + 240
frame #2: 0x0000000113111f54 rspack.darwin-arm64.node`<rspack_binding_api::build_info::BuildInfo as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value + 200
frame #3: 0x0000000112fbca94 rspack.darwin-arm64.node`<rspack_binding_api::modules::normal_module::NormalModule>::new_inherited::build_info_getter + 436
frame #4: 0x000000010008a108 node`v8impl::(anonymous namespace)::FunctionCallbackWrapper::Invoke(v8::FunctionCallbackInfo<v8::Value> const&) + 104
frame #5: 0x00000001002ca49c node`v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) + 192
frame #6: 0x00000001002c9ffc node`v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) + 448
frame #7: 0x00000001002c9aa8 node`v8::internal::Builtins::InvokeApiFunction(v8::internal::Isolate*, bool, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, v8::internal::Handle<v8::internal::HeapObject>) + 460
frame #8: 0x00000001003a1550 node`v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) + 428
frame #9: 0x00000001003a138c node`v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*) + 196
frame #10: 0x00000001006b7a7c node`v8::internal::Object::GetPropertyWithAccessor(v8::internal::LookupIterator*) + 860
frame #11: 0x00000001006b7044 node`v8::internal::Object::GetProperty(v8::internal::LookupIterator*, bool) + 332
frame #12: 0x00000001007c47f8 node`v8::internal::Runtime::GetObjectProperty(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, bool*) + 192
frame #13: 0x00000001007c6b44 node`v8::internal::Runtime_GetProperty(int, unsigned long*, v8::internal::Isolate*) + 932
frame #14: 0x0000000100b3510c node`Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit + 108
frame #15: 0x0000000105318050
frame #16: 0x0000000100af1ef4 node`Builtins_AsyncFunctionAwaitResolveClosure + 84
frame #17: 0x0000000100b80838 node`Builtins_PromiseFulfillReactionJob + 56
frame #18: 0x0000000100ae3c4c node`Builtins_RunMicrotasks + 588
frame #19: 0x0000000100abe3a4 node`Builtins_JSRunMicrotasksEntry + 164
frame #20: 0x00000001003a1d74 node`v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) + 2512
frame #21: 0x00000001003a2368 node`v8::internal::(anonymous namespace)::InvokeWithTryCatch(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) + 88
frame #22: 0x00000001003a2554 node`v8::internal::Execution::TryRunMicrotasks(v8::internal::Isolate*, v8::internal::MicrotaskQueue*, v8::internal::MaybeHandle<v8::internal::Object>*) + 64
frame #23: 0x00000001003cc3f4 node`v8::internal::MicrotaskQueue::RunMicrotasks(v8::internal::Isolate*) + 336
frame #24: 0x00000001003ccb80 node`v8::internal::MicrotaskQueue::PerformCheckpoint(v8::Isolate*) + 124
frame #25: 0x0000000100004c84 node`node::InternalCallbackScope::Close() + 256
frame #26: 0x000000010000482c node`node::CallbackScope::~CallbackScope() + 64
frame #27: 0x000000010009b3c0 node`(anonymous namespace)::uvimpl::Work::AfterThreadPoolWork(int) + 412
frame #28: 0x000000010009b7ec node`node::ThreadPoolWork::ScheduleWork()::'lambda'(uv_work_s*, int)::operator()(uv_work_s*, int) const + 320
frame #29: 0x000000010009b6a0 node`node::ThreadPoolWork::ScheduleWork()::'lambda'(uv_work_s*, int)::__invoke(uv_work_s*, int) + 28
frame #30: 0x0000000100a98f84 node`uv__work_done + 192
frame #31: 0x0000000100a9c6e8 node`uv__async_io + 320
frame #32: 0x0000000100aaf8dc node`uv__io_poll + 1044
frame #33: 0x0000000100a9cba0 node`uv_run + 388
frame #34: 0x00000001000057e0 node`node::SpinEventLoop(node::Environment*) + 248
frame #35: 0x000000010011097c node`node::NodeMainInstance::Run() + 200
frame #36: 0x0000000100095938 node`node::LoadSnapshotDataAndRun(node::SnapshotData const**, node::InitializationResult const*) + 456
frame #37: 0x0000000100095b60 node`node::Start(int, char**) + 468
frame #38: 0x0000000185936b98 dyld`start + 6076
Crash 2: SIGABRT (unsafe precondition violated)
context: /Users/edson.lin/Desktop/SourceCode/editor
Panic occurred at runtime. Please file an issue on GitHub with the backtrace below: https://github.com/web-infra-dev/rspack/issues: panicked at /Users/runner/.rustup/toolchains/nightly-2025-11-13-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:1639:18:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
thread caused non-unwinding panic. aborting.
Process 15455 launched: '/Users/edson.lin/.nvm/versions/node/v18.20.8/bin/node' (arm64)
Process 15455 stopped
* thread #1, name = 'rsbuild-node', queue = 'com.apple.main-thread', stop reason = signal SIGABRT
frame #0: 0x0000000185c9e388 libsystem_kernel.dylib`__pthread_kill + 8
libsystem_kernel.dylib`__pthread_kill:
-> 0x185c9e388 <+8>: b.lo 0x185c9e3a8 ; <+40>
0x185c9e38c <+12>: pacibsp
0x185c9e390 <+16>: stp x29, x30, [sp, #-0x10]!
0x185c9e394 <+20>: mov x29, sp
Target 0: (node) stopped.
(lldb) dt
error: 'dt' is not a valid command.
(lldb) bt
* thread #1, name = 'rsbuild-node', queue = 'com.apple.main-thread', stop reason = signal SIGABRT
* frame #0: 0x0000000185c9e388 libsystem_kernel.dylib`__pthread_kill + 8
frame #1: 0x0000000185cd7848 libsystem_pthread.dylib`pthread_kill + 296
frame #2: 0x0000000185be09e4 libsystem_c.dylib`abort + 124
frame #3: 0x0000000135168344 rspack.darwin-arm64.node`std::sys::pal::unix::abort_internal + 12
frame #4: 0x0000000135167d38 rspack.darwin-arm64.node`std::process::abort + 12
frame #5: 0x0000000134fa2b18 rspack.darwin-arm64.node`std::panicking::panic_with_hook + 872
frame #6: 0x0000000134fa18bc rspack.darwin-arm64.node`std::panicking::panic_handler::{closure#0} + 100
frame #7: 0x0000000134fa1490 rspack.darwin-arm64.node`std::sys::backtrace::__rust_end_short_backtrace::<std::panicking::panic_handler::{closure#0}, !> + 12
frame #8: 0x0000000134fa1b14 rspack.darwin-arm64.node`__rustc::rust_begin_unwind + 32
frame #9: 0x000000013516a348 rspack.darwin-arm64.node`core::panicking::panic_nounwind_fmt + 52
frame #10: 0x0000000134f3ed3c rspack.darwin-arm64.node`<indexmap::map::IndexMap<alloc::string::String, serde_json::value::Value>>::iter + 152
frame #11: 0x0000000134f262b0 rspack.darwin-arm64.node`<&serde_json::map::Map<alloc::string::String, serde_json::value::Value> as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value + 104
frame #12: 0x00000001321c98a0 rspack.darwin-arm64.node`<rspack_binding_api::build_info::BuildInfo>::with_ref::<(), <rspack_binding_api::build_info::BuildInfo as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value::{closure#0}::{closure#1}> + 204
frame #13: 0x000000013209f144 rspack.darwin-arm64.node`<std::thread::local::LocalKey<core::cell::RefCell<alloc::vec::Vec<napi::js_values::object_property::Property>>>>::with::<<rspack_binding_api::build_info::BuildInfo as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value::{closure#0}, core::result::Result<(), napi::error::Error>> + 240
frame #14: 0x0000000132215f54 rspack.darwin-arm64.node`<rspack_binding_api::build_info::BuildInfo as napi::bindgen_runtime::js_values::ToNapiValue>::to_napi_value + 200
frame #15: 0x00000001320c0a94 rspack.darwin-arm64.node`<rspack_binding_api::modules::normal_module::NormalModule>::new_inherited::build_info_getter + 436
frame #16: 0x000000010008a108 node`v8impl::(anonymous namespace)::FunctionCallbackWrapper::Invoke(v8::FunctionCallbackInfo<v8::Value> const&) + 104
frame #17: 0x00000001002ca49c node`v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) + 192
frame #18: 0x00000001002c9ffc node`v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) + 448
frame #19: 0x00000001002c9aa8 node`v8::internal::Builtins::InvokeApiFunction(v8::internal::Isolate*, bool, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, v8::internal::Handle<v8::internal::HeapObject>) + 460
frame #20: 0x00000001003a1550 node`v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) + 428
frame #21: 0x00000001003a138c node`v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*) + 196
frame #22: 0x00000001006b7a7c node`v8::internal::Object::GetPropertyWithAccessor(v8::internal::LookupIterator*) + 860
frame #23: 0x00000001006b7044 node`v8::internal::Object::GetProperty(v8::internal::LookupIterator*, bool) + 332
frame #24: 0x00000001007c47f8 node`v8::internal::Runtime::GetObjectProperty(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, bool*) + 192
frame #25: 0x00000001007c6b44 node`v8::internal::Runtime_GetProperty(int, unsigned long*, v8::internal::Isolate*) + 932
frame #26: 0x0000000100b3510c node`Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit + 108
frame #27: 0x00000001058264f8
frame #28: 0x0000000100af1ef4 node`Builtins_AsyncFunctionAwaitResolveClosure + 84
frame #29: 0x0000000100b80838 node`Builtins_PromiseFulfillReactionJob + 56
frame #30: 0x0000000100ae3c4c node`Builtins_RunMicrotasks + 588
frame #31: 0x0000000100abe3a4 node`Builtins_JSRunMicrotasksEntry + 164
frame #32: 0x00000001003a1d74 node`v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) + 2512
frame #33: 0x00000001003a2368 node`v8::internal::(anonymous namespace)::InvokeWithTryCatch(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) + 88
frame #34: 0x00000001003a2554 node`v8::internal::Execution::TryRunMicrotasks(v8::internal::Isolate*, v8::internal::MicrotaskQueue*, v8::internal::MaybeHandle<v8::internal::Object>*) + 64
frame #35: 0x00000001003cc3f4 node`v8::internal::MicrotaskQueue::RunMicrotasks(v8::internal::Isolate*) + 336
frame #36: 0x00000001003ccb80 node`v8::internal::MicrotaskQueue::PerformCheckpoint(v8::Isolate*) + 124
frame #37: 0x0000000100004c84 node`node::InternalCallbackScope::Close() + 256
frame #38: 0x000000010000482c node`node::CallbackScope::~CallbackScope() + 64
frame #39: 0x000000010009b3c0 node`(anonymous namespace)::uvimpl::Work::AfterThreadPoolWork(int) + 412
frame #40: 0x000000010009b7ec node`node::ThreadPoolWork::ScheduleWork()::'lambda'(uv_work_s*, int)::operator()(uv_work_s*, int) const + 320
frame #41: 0x000000010009b6a0 node`node::ThreadPoolWork::ScheduleWork()::'lambda'(uv_work_s*, int)::__invoke(uv_work_s*, int) + 28
frame #42: 0x0000000100a98f84 node`uv__work_done + 192
frame #43: 0x0000000100a9c6e8 node`uv__async_io + 320
frame #44: 0x0000000100aaf8dc node`uv__io_poll + 1044
frame #45: 0x0000000100a9cba0 node`uv_run + 388
frame #46: 0x00000001000057e0 node`node::SpinEventLoop(node::Environment*) + 248
frame #47: 0x000000010011097c node`node::NodeMainInstance::Run() + 200
frame #48: 0x0000000100095938 node`node::LoadSnapshotDataAndRun(node::SnapshotData const**, node::InitializationResult const*) + 456
frame #49: 0x0000000100095b60 node`node::Start(int, char**) + 468
frame #50: 0x0000000185936b98 dyld`start + 6076
Analysis
The crash occurs in rspack_binding_api/src/build_info.rs:
// line 136-150
fn with_ref<T>(
&mut self,
f: impl FnOnce(&dyn rspack_core::Module) -> napi::Result<T>,
) -> napi::Result<T> {
match self.module_reference.get_mut() {
Some(reference) => {
let (_, module) = reference.as_ref()?; // 🔥 CRASH HERE
f(module)
}
None => Err(...)
}
}The issue: BuildInfo holds a WeakReference<Module> (line 122). The with_ref method checks if the JavaScript object is still alive via get_mut(), but this doesn't protect against the underlying Rust data being invalidated by another thread.
Race condition diagram
┌─────────────────────────────────────────────────────────────────┐
│ Thread A (Loader Runner) │
│ - Processing/rebuilding module │
│ - Module's Rust data is dropped/moved/reallocated │
│ │
│ Thread B (JS Callback / Promise resolution) │
│ - WeakReference.get_mut() → Some(reference) ✅ │
│ (JS wrapper object still exists) │
│ - reference.as_ref() → 💥 SIGBUS │
│ (Rust data pointer is now invalid!) │
└─────────────────────────────────────────────────────────────────┘
Reproduce link
No response
Reproduce Steps
npm run dev
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
pending triageThe issue/PR is currently untouched.The issue/PR is currently untouched.