have name in crash handler

This commit is contained in:
Zack Radisic
2024-11-27 18:38:39 -08:00
parent def9582019
commit 4e2fcbb257
4 changed files with 68 additions and 40 deletions

View File

@@ -122,14 +122,27 @@ pub const JSBundler = struct {
return globalThis.throwInvalidArguments("Expected plugin to be an object", .{});
}
if (try plugin.getOptional(globalThis, "name", ZigString.Slice)) |slice| {
defer slice.deinit();
if (slice.len == 0) {
const name = name: {
var raw_val = try plugin.get(globalThis, "name") orelse {
return globalThis.throwInvalidArguments("Expected plugin to have a name", .{});
};
if (!raw_val.isString()) {
return globalThis.throwInvalidArguments("Expected plugin to have a name", .{});
}
const bunstr: bun.String = try raw_val.toBunString2(globalThis);
if (bunstr.length() == 0) {
bunstr.deref();
return globalThis.throwInvalidArguments("Expected plugin to have a non-empty name", .{});
}
} else {
return globalThis.throwInvalidArguments("Expected plugin to have a name", .{});
}
if (bunstr.tag != .WTFStringImpl) {
var new_bun_str = raw_val.toBunString(globalThis);
new_bun_str.toWTF();
break :name new_bun_str;
}
break :name bunstr;
};
defer name.deref();
bun.debugAssert(name.tag == .WTFStringImpl);
const function = try plugin.getFunction(globalThis, "setup") orelse {
return globalThis.throwInvalidArguments("Expected plugin to have a setup() function", .{});
@@ -138,6 +151,7 @@ pub const JSBundler = struct {
var bun_plugins: *Plugin = plugins.* orelse brk: {
plugins.* = Plugin.create(
globalThis,
name.value.WTFStringImpl,
switch (this.target) {
.bun, .bun_macro => JSC.JSGlobalObject.BunPluginTarget.bun,
.node => JSC.JSGlobalObject.BunPluginTarget.node,
@@ -924,10 +938,10 @@ pub const JSBundler = struct {
};
pub const Plugin = opaque {
extern fn JSBundlerPlugin__create(*JSC.JSGlobalObject, JSC.JSGlobalObject.BunPluginTarget) *Plugin;
pub fn create(globalObject: *JSC.JSGlobalObject, target: JSC.JSGlobalObject.BunPluginTarget) *Plugin {
extern fn JSBundlerPlugin__create(*JSC.JSGlobalObject, bun.WTF.StringImpl, JSC.JSGlobalObject.BunPluginTarget) *Plugin;
pub fn create(globalObject: *JSC.JSGlobalObject, name: bun.WTF.StringImpl, target: JSC.JSGlobalObject.BunPluginTarget) *Plugin {
JSC.markBinding(@src());
const plugin = JSBundlerPlugin__create(globalObject, target);
const plugin = JSBundlerPlugin__create(globalObject, name, target);
JSC.JSValue.fromCell(plugin).protect();
return plugin;
}

View File

@@ -113,20 +113,20 @@ static const HashTableValue JSBundlerPluginHashTable[] = {
{ "generateDeferPromise"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBundlerPluginFunction_generateDeferPromise, 0 } },
};
class JSBundlerPlugin final : public JSC::JSNonFinalObject {
public:
using Base = JSC::JSNonFinalObject;
static JSBundlerPlugin* create(JSC::VM& vm,
JSC::JSGlobalObject* globalObject,
JSC::Structure* structure,
WTF::StringImpl* name,
void* config,
BunPluginTarget target,
JSBundlerPluginAddErrorCallback addError = JSBundlerPlugin__addError,
JSBundlerPluginOnLoadAsyncCallback onLoadAsync = JSBundlerPlugin__onLoadAsync,
JSBundlerPluginOnResolveAsyncCallback onResolveAsync = JSBundlerPlugin__onResolveAsync)
{
JSBundlerPlugin* ptr = new (NotNull, JSC::allocateCell<JSBundlerPlugin>(vm)) JSBundlerPlugin(vm, globalObject, structure, config, target,
JSBundlerPlugin* ptr = new (NotNull, JSC::allocateCell<JSBundlerPlugin>(vm)) JSBundlerPlugin(vm, globalObject, structure, name, config, target,
addError,
onLoadAsync,
onResolveAsync);
@@ -161,10 +161,10 @@ public:
WTF::HashMap<WTF::String, void*> onBeforeParseHandles;
private:
JSBundlerPlugin(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure, void* config, BunPluginTarget target,
JSBundlerPlugin(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure, WTF::StringImpl* name, void* config, BunPluginTarget target,
JSBundlerPluginAddErrorCallback addError, JSBundlerPluginOnLoadAsyncCallback onLoadAsync, JSBundlerPluginOnResolveAsyncCallback onResolveAsync)
: JSC::JSNonFinalObject(vm, structure)
, plugin(BundlerPlugin(config, target, addError, onLoadAsync, onResolveAsync))
, plugin(BundlerPlugin(config, name, target, addError, onLoadAsync, onResolveAsync))
{
}
@@ -250,21 +250,20 @@ void BundlerPlugin::NativePluginList::append(JSC::VM& vm, JSC::RegExp* filter, S
nsGroup->append(nativeFilterRegexp);
}
if (index == std::numeric_limits<unsigned>::max()) {
this->fileCallbacks.append(NativePluginCallback{callback, external});
this->fileCallbacks.append(NativePluginCallback { callback, external });
} else {
if (this->namespaceCallbacks.size() <= index) {
this->namespaceCallbacks.grow(index + 1);
}
this->namespaceCallbacks[index].append(NativePluginCallback{callback, external});
this->namespaceCallbacks[index].append(NativePluginCallback { callback, external });
}
}
extern "C" void CrashHandler__setInsideNativePlugin(bool value);
extern "C" void CrashHandler__setInsideNativePlugin(bool value, const char* plugin_name);
int BundlerPlugin::NativePluginList::call(JSC::VM& vm, int* shouldContinue, void* bunContextPtr, const BunString* namespaceStr, const BunString* pathString, void* onBeforeParseArgs, void* onBeforeParseResult)
int BundlerPlugin::NativePluginList::call(JSC::VM& vm, BundlerPlugin* plugin, int* shouldContinue, void* bunContextPtr, const BunString* namespaceStr, const BunString* pathString, void* onBeforeParseArgs, void* onBeforeParseResult)
{
unsigned index = 0;
const auto* group = this->group(namespaceStr->toWTFString(BunString::ZeroCopy), index);
@@ -281,6 +280,11 @@ int BundlerPlugin::NativePluginList::call(JSC::VM& vm, int* shouldContinue, void
int count = 0;
constexpr bool usesPatternContextBuffer = false;
const WTF::String& path = pathString->toWTFString(BunString::ZeroCopy);
if (!plugin->name_c.has_value()) {
auto plugin_name_c = plugin->name->utf8();
plugin->name_c = std::make_optional(plugin_name_c);
}
CString& plugin_name = plugin->name_c.value();
for (size_t i = 0, total = callbacks.size(); i < total && *shouldContinue; ++i) {
Yarr::MatchingContextHolder regExpContext(vm, usesPatternContextBuffer, nullptr, Yarr::MatchFrom::CompilerThread);
@@ -289,13 +293,13 @@ int BundlerPlugin::NativePluginList::call(JSC::VM& vm, int* shouldContinue, void
if (group->at(i).first.match(path) > -1) {
Bun::NapiExternal* external = callbacks[i].external;
if (external) {
((OnBeforeParseArguments*) (onBeforeParseArgs))->external = external->value();
((OnBeforeParseArguments*)(onBeforeParseArgs))->external = external->value();
}
JSBundlerPluginNativeOnBeforeParseCallback callback = callbacks[i].callback;
CrashHandler__setInsideNativePlugin(true);
CrashHandler__setInsideNativePlugin(true, plugin_name.data());
callback(onBeforeParseArgs, onBeforeParseResult);
CrashHandler__setInsideNativePlugin(false);
CrashHandler__setInsideNativePlugin(false, nullptr);
count++;
}
@@ -352,7 +356,7 @@ JSC_DEFINE_HOST_FUNCTION(jsBundlerPluginFunction_onBeforeParse, (JSC::JSGlobalOb
Bun::NapiModuleMeta* meta = (Bun::NapiModuleMeta*)napi_external->value();
void* dlopen_handle = meta->dlopenHandle;
#if OS(WINDOWS)
#if OS(WINDOWS)
BunString onbefore_parse_symbol_str = Bun::toString(on_before_parse_symbol);
void* on_before_parse_symbol_ptr = GetProcAddress(&onbefore_parse_symbol_str);
#else
@@ -560,7 +564,7 @@ extern "C" void JSBundlerPlugin__matchOnResolve(JSC::JSGlobalObject* globalObjec
}
}
extern "C" Bun::JSBundlerPlugin* JSBundlerPlugin__create(Zig::GlobalObject* globalObject, BunPluginTarget target)
extern "C" Bun::JSBundlerPlugin* JSBundlerPlugin__create(Zig::GlobalObject* globalObject, WTF::StringImpl* name, BunPluginTarget target)
{
return JSBundlerPlugin::create(
globalObject->vm(),
@@ -570,6 +574,7 @@ extern "C" Bun::JSBundlerPlugin* JSBundlerPlugin__create(Zig::GlobalObject* glob
globalObject->vm(),
globalObject,
globalObject->objectPrototype()),
name,
nullptr,
target);
}
@@ -634,7 +639,7 @@ extern "C" int JSBundlerPlugin__callOnBeforeParsePlugins(
void* onBeforeParseResult,
int* shouldContinue)
{
return plugin->plugin.onBeforeParse.call(plugin->vm(), shouldContinue, bunContextPtr, namespaceStr, pathString, onBeforeParseArgs, onBeforeParseResult);
return plugin->plugin.onBeforeParse.call(plugin->vm(), &plugin->plugin, shouldContinue, bunContextPtr, namespaceStr, pathString, onBeforeParseArgs, onBeforeParseResult);
}
extern "C" int JSBundlerPlugin__hasOnBeforeParsePlugins(Bun::JSBundlerPlugin* plugin)

View File

@@ -10,7 +10,7 @@
typedef void (*JSBundlerPluginAddErrorCallback)(void*, void*, JSC::EncodedJSValue, JSC::EncodedJSValue);
typedef void (*JSBundlerPluginOnLoadAsyncCallback)(void*, void*, JSC::EncodedJSValue, JSC::EncodedJSValue);
typedef void (*JSBundlerPluginOnResolveAsyncCallback)(void*, void*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::EncodedJSValue);
typedef void (*JSBundlerPluginNativeOnBeforeParseCallback)( void*, void*);
typedef void (*JSBundlerPluginNativeOnBeforeParseCallback)(void*, void*);
namespace Bun {
@@ -46,7 +46,7 @@ public:
void append(JSC::VM& vm, JSC::RegExp* filter, String& namespaceString, unsigned& index);
};
#include "../../../packages/bun-native-bundler-plugin-api/bundler_plugin.h"
#include "../../../packages/bun-native-bundler-plugin-api/bundler_plugin.h"
/// In native plugins, the regular expression could be called concurrently on multiple threads.
/// Therefore, we need a mutex to synchronize access.
@@ -69,7 +69,7 @@ public:
PerNamespaceCallbackList fileCallbacks = {};
Vector<PerNamespaceCallbackList> namespaceCallbacks = {};
int call(JSC::VM& vm, int* shouldContinue, void* bunContextPtr, const BunString* namespaceStr, const BunString* pathString, void* onBeforeParseArgs, void* onBeforeParseResult);
int call(JSC::VM& vm, BundlerPlugin* plugin, int* shouldContinue, void* bunContextPtr, const BunString* namespaceStr, const BunString* pathString, void* onBeforeParseArgs, void* onBeforeParseResult);
void append(JSC::VM& vm, JSC::RegExp* filter, String& namespaceString, JSBundlerPluginNativeOnBeforeParseCallback callback, NapiExternal* external);
Vector<NativeFilterRegexp>* group(const String& namespaceStr, unsigned& index)
@@ -95,15 +95,18 @@ public:
bool anyMatchesCrossThread(JSC::VM&, const BunString* namespaceStr, const BunString* path, bool isOnLoad);
void tombstone() { tombstoned = true; }
BundlerPlugin(void* config, BunPluginTarget target, JSBundlerPluginAddErrorCallback addError, JSBundlerPluginOnLoadAsyncCallback onLoadAsync, JSBundlerPluginOnResolveAsyncCallback onResolveAsync)
BundlerPlugin(void* config, WTF::StringImpl* name, BunPluginTarget target, JSBundlerPluginAddErrorCallback addError, JSBundlerPluginOnLoadAsyncCallback onLoadAsync, JSBundlerPluginOnResolveAsyncCallback onResolveAsync)
: addError(addError)
, onLoadAsync(onLoadAsync)
, onResolveAsync(onResolveAsync)
{
this->name = name;
this->target = target;
this->config = config;
}
WTF::StringImpl* name;
std::optional<CString> name_c = {};
NamespaceList onLoad = {};
NamespaceList onResolve = {};
NativePluginList onBeforeParse = {};

View File

@@ -51,9 +51,11 @@ var panic_mutex = std.Thread.Mutex{};
threadlocal var panic_stage: usize = 0;
threadlocal var inside_native_plugin: bool = false;
threadlocal var inside_native_plugin_str: ?[*:0]const u8 = null;
export fn CrashHandler__setInsideNativePlugin(value: bool) callconv(.C) void {
export fn CrashHandler__setInsideNativePlugin(value: bool, name: ?[*:0]const u8) callconv(.C) void {
inside_native_plugin = value;
inside_native_plugin_str = name;
}
/// This can be set by various parts of the codebase to indicate a broader
@@ -233,14 +235,17 @@ 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();
if (inside_native_plugin) {
const native_plugin_name = inside_native_plugin_str orelse "<unknown>";
writer.print(
\\
\\Bun has encountered a crash while running the "{s}" native plugin.
\\
\\This indicates either a bug in the native plugin or in Bun.
\\
\\
, .{native_plugin_name}) catch std.posix.abort();
}
} else {
if (Output.enable_ansi_colors) {
writer.writeAll(Output.prettyFmt("<red>", true)) catch std.posix.abort();
@@ -324,14 +329,15 @@ pub fn crashHandler(
writer.writeAll(Output.prettyFmt(": ", true)) catch std.posix.abort();
}
if (inside_native_plugin) {
const native_plugin_name = inside_native_plugin_str orelse "<unknown>";
writer.print(
\\Bun has encountered a crash while running a native plugin.
\\Bun has encountered a crash while running the "{s}" 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();
, .{native_plugin_name}) catch std.posix.abort();
} else if (reason == .out_of_memory) {
writer.writeAll(
\\Bun has ran out of memory.