mirror of
https://github.com/oven-sh/bun
synced 2026-02-14 12:51:54 +00:00
update crash handler to log when a native plugin has crashed
This commit is contained in:
@@ -290,7 +290,7 @@ impl<'a> OnBeforeParse<'a> {
|
||||
}
|
||||
|
||||
/// Get the output loader for the current file.
|
||||
pub fn output_loader(&self) -> BunLogLevel {
|
||||
pub fn output_loader(&self) -> BunLoader {
|
||||
unsafe { std::mem::transmute(self.result_raw.loader as u32) }
|
||||
}
|
||||
|
||||
|
||||
@@ -430,7 +430,8 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen,
|
||||
|
||||
|
||||
// TODO: think about the finalizer here
|
||||
Bun::NapiExternal* napi_external = Bun::NapiExternal::create(vm, globalObject->NapiExternalStructure(), globalObject->m_pendingNapiModuleDlopenHandle, nullptr, nullptr);
|
||||
auto *meta = new Bun::NapiModuleMeta(globalObject->m_pendingNapiModuleDlopenHandle);
|
||||
Bun::NapiExternal* napi_external = Bun::NapiExternal::create(vm, globalObject->NapiExternalStructure(), meta, nullptr, nullptr);
|
||||
bool success = resultValue.getObject()->putDirect(vm, WebCore::builtinNames(vm).napiDlopenHandlePrivateName(), napi_external, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
|
||||
ASSERT(success);
|
||||
|
||||
|
||||
@@ -252,15 +252,18 @@ void BundlerPlugin::NativePluginList::append(JSC::VM& vm, JSC::RegExp* filter, S
|
||||
}
|
||||
|
||||
if (index == std::numeric_limits<unsigned>::max()) {
|
||||
this->fileCallbacks.append(std::make_pair(callback, external));
|
||||
this->fileCallbacks.append(NativePluginCallback{callback, external});
|
||||
} else {
|
||||
if (this->namespaceCallbacks.size() <= index) {
|
||||
this->namespaceCallbacks.grow(index + 1);
|
||||
}
|
||||
this->namespaceCallbacks[index].append(std::make_pair(callback, external));
|
||||
this->namespaceCallbacks[index].append(NativePluginCallback{callback, external});
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void CrashHandler__setInsideNativePlugin(bool value);
|
||||
|
||||
|
||||
int BundlerPlugin::NativePluginList::call(JSC::VM& vm, int* shouldContinue, void* bunContextPtr, const BunString* namespaceStr, const BunString* pathString, void* onBeforeParseArgs, void* onBeforeParseResult)
|
||||
{
|
||||
unsigned index = 0;
|
||||
@@ -284,11 +287,16 @@ int BundlerPlugin::NativePluginList::call(JSC::VM& vm, int* shouldContinue, void
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*group->at(i).second);
|
||||
if (group->at(i).first.match(path) > -1) {
|
||||
Bun::NapiExternal* external = callbacks[i].second;
|
||||
Bun::NapiExternal* external = callbacks[i].external;
|
||||
if (external) {
|
||||
((OnBeforeParseArguments*) (onBeforeParseArgs))->external = external->value();
|
||||
}
|
||||
callbacks[i].first(onBeforeParseArgs, onBeforeParseResult);
|
||||
|
||||
JSBundlerPluginNativeOnBeforeParseCallback callback = callbacks[i].callback;
|
||||
CrashHandler__setInsideNativePlugin(true);
|
||||
callback(onBeforeParseArgs, onBeforeParseResult);
|
||||
CrashHandler__setInsideNativePlugin(false);
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -335,12 +343,14 @@ JSC_DEFINE_HOST_FUNCTION(jsBundlerPluginFunction_onBeforeParse, (JSC::JSGlobalOb
|
||||
}
|
||||
WTF::String on_before_parse_symbol = on_before_parse_symbol_js.toWTFString(globalObject);
|
||||
|
||||
// The dlopen *void handle is attached to the node_addon as a NapiExternal
|
||||
Bun::NapiExternal* napi_external = jsDynamicCast<Bun::NapiExternal*>(node_addon.getObject()->get(globalObject, WebCore::builtinNames(vm).napiDlopenHandlePrivateName()));
|
||||
if (UNLIKELY(!napi_external)) {
|
||||
Bun::throwError(globalObject, scope, ErrorCode::ERR_INVALID_ARG_TYPE, "Expected node_addon (2nd argument) to have a napiDlopenHandle property"_s);
|
||||
return {};
|
||||
}
|
||||
void* dlopen_handle = napi_external->value();
|
||||
Bun::NapiModuleMeta* meta = (Bun::NapiModuleMeta*)napi_external->value();
|
||||
void* dlopen_handle = meta->dlopenHandle;
|
||||
|
||||
#if OS(WINDOWS)
|
||||
BunString onbefore_parse_symbol_str = Bun::toString(on_before_parse_symbol);
|
||||
|
||||
@@ -52,9 +52,14 @@ public:
|
||||
/// Therefore, we need a mutex to synchronize access.
|
||||
typedef std::pair<Yarr::RegularExpression, std::shared_ptr<std::mutex>> NativeFilterRegexp;
|
||||
|
||||
struct NativePluginCallback {
|
||||
JSBundlerPluginNativeOnBeforeParseCallback callback;
|
||||
Bun::NapiExternal* external;
|
||||
};
|
||||
|
||||
class NativePluginList {
|
||||
public:
|
||||
using PerNamespaceCallbackList = Vector<std::pair<JSBundlerPluginNativeOnBeforeParseCallback, Bun::NapiExternal*>>;
|
||||
using PerNamespaceCallbackList = Vector<NativePluginCallback>;
|
||||
|
||||
Vector<NativeFilterRegexp> fileNamespace = {};
|
||||
Vector<String> namespaces = {};
|
||||
|
||||
@@ -1005,8 +1005,10 @@ extern "C" void napi_module_register(napi_module* mod)
|
||||
return;
|
||||
}
|
||||
|
||||
auto *meta = new Bun::NapiModuleMeta(globalObject->m_pendingNapiModuleDlopenHandle);
|
||||
|
||||
// TODO: think about the finalizer here
|
||||
Bun::NapiExternal* napi_external = Bun::NapiExternal::create(vm, globalObject->NapiExternalStructure(), globalObject->m_pendingNapiModuleDlopenHandle, nullptr, nullptr);
|
||||
Bun::NapiExternal* napi_external = Bun::NapiExternal::create(vm, globalObject->NapiExternalStructure(), meta, nullptr, nullptr);
|
||||
|
||||
bool success = resultValue.getObject()->putDirect(vm, WebCore::builtinNames(vm).napiDlopenHandlePrivateName(), napi_external, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
|
||||
ASSERT(success);
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace Bun {
|
||||
using namespace JSC;
|
||||
using namespace WebCore;
|
||||
|
||||
typedef struct {
|
||||
/// The result of call to dlopen to load the module
|
||||
void* dlopenHandle;
|
||||
} NapiModuleMeta;
|
||||
|
||||
class NapiExternal : public JSC::JSDestructibleObject {
|
||||
using Base = JSC::JSDestructibleObject;
|
||||
|
||||
|
||||
@@ -50,6 +50,12 @@ var panic_mutex = std.Thread.Mutex{};
|
||||
/// This is used to catch and handle panics triggered by the panic handler.
|
||||
threadlocal var panic_stage: usize = 0;
|
||||
|
||||
threadlocal var inside_native_plugin: bool = false;
|
||||
|
||||
export fn CrashHandler__setInsideNativePlugin(value: bool) callconv(.C) void {
|
||||
inside_native_plugin = value;
|
||||
}
|
||||
|
||||
/// This can be set by various parts of the codebase to indicate a broader
|
||||
/// action being taken. It is printed when a crash happens, which can help
|
||||
/// narrow down what the bug is. Example: "Crashed while parsing /path/to/file.js"
|
||||
@@ -226,6 +232,15 @@ pub fn crashHandler(
|
||||
|
||||
writer.writeAll("=" ** 60 ++ "\n") catch std.posix.abort();
|
||||
printMetadata(writer) catch std.posix.abort();
|
||||
|
||||
writer.print(
|
||||
\\
|
||||
\\Bun has encountered a crash while running the a native plugin.
|
||||
\\
|
||||
\\This indicates either a bug in the native plugin or in Bun.
|
||||
\\
|
||||
\\
|
||||
, .{}) catch std.posix.abort();
|
||||
} else {
|
||||
if (Output.enable_ansi_colors) {
|
||||
writer.writeAll(Output.prettyFmt("<red>", true)) catch std.posix.abort();
|
||||
@@ -308,7 +323,16 @@ pub fn crashHandler(
|
||||
} else {
|
||||
writer.writeAll(Output.prettyFmt(": ", true)) catch std.posix.abort();
|
||||
}
|
||||
if (reason == .out_of_memory) {
|
||||
if (inside_native_plugin) {
|
||||
writer.print(
|
||||
\\Bun has encountered a crash while running a native plugin.
|
||||
\\
|
||||
\\To send a redacted crash report to Bun's team,
|
||||
\\please file a GitHub issue using the link below:
|
||||
\\
|
||||
\\
|
||||
, .{}) catch std.posix.abort();
|
||||
} else if (reason == .out_of_memory) {
|
||||
writer.writeAll(
|
||||
\\Bun has ran out of memory.
|
||||
\\
|
||||
@@ -737,6 +761,7 @@ fn handleSegfaultPosix(sig: i32, info: *const std.posix.siginfo_t, _: ?*const an
|
||||
std.posix.SIG.ILL => .{ .illegal_instruction = addr },
|
||||
std.posix.SIG.BUS => .{ .bus_error = addr },
|
||||
std.posix.SIG.FPE => .{ .floating_point_error = addr },
|
||||
std.posix.SIG.KILL => .{ .segmentation_fault = addr },
|
||||
|
||||
// we do not register this handler for other signals
|
||||
else => unreachable,
|
||||
|
||||
Reference in New Issue
Block a user