mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
fix bugs (#1795)
- segfault reading stacktrace from `fs/promises` rejections - `Promise` rejection within `describe()` ends testing abruptly - `FSSink.write()` incorrectly handles `objectMode` - `FSSink.write()` throws wrong error codes
This commit is contained in:
@@ -1848,8 +1848,11 @@ pub const VirtualMachine = struct {
|
||||
|
||||
const message = exception.message;
|
||||
var did_print_name = false;
|
||||
if (source_lines.next()) |source| {
|
||||
if (source.text.len > 0 and exception.stack.frames()[0].position.isInvalid()) {
|
||||
if (source_lines.next()) |source| brk: {
|
||||
if (source.text.len == 0) break :brk;
|
||||
|
||||
const top_frame = if (exception.stack.frames_len > 0) exception.stack.frames()[0] else null;
|
||||
if (top_frame == null or top_frame.?.position.isInvalid()) {
|
||||
defer did_print_name = true;
|
||||
var text = std.mem.trim(u8, source.text, "\n");
|
||||
|
||||
@@ -1864,12 +1867,11 @@ pub const VirtualMachine = struct {
|
||||
);
|
||||
|
||||
try this.printErrorNameAndMessage(name, message, Writer, writer, allow_ansi_color);
|
||||
} else if (source.text.len > 0) {
|
||||
} else if (top_frame) |top| {
|
||||
defer did_print_name = true;
|
||||
const int_size = std.fmt.count("{d}", .{source.line});
|
||||
const pad = max_line_number_pad - int_size;
|
||||
try writer.writeByteNTimes(' ', pad);
|
||||
const top = exception.stack.frames()[0];
|
||||
var remainder = std.mem.trim(u8, source.text, "\n");
|
||||
|
||||
try writer.print(
|
||||
|
||||
@@ -2028,14 +2028,13 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
|
||||
const args_list = callframe.arguments(4);
|
||||
const args = args_list.ptr[0..args_list.len];
|
||||
|
||||
if (args.len == 0 or args[0].isEmptyOrUndefinedOrNull() or args[0].isNumber()) {
|
||||
const err = JSC.toTypeError(
|
||||
if (args.len == 0) JSC.Node.ErrorCode.ERR_MISSING_ARGS else JSC.Node.ErrorCode.ERR_INVALID_ARG_TYPE,
|
||||
if (args.len == 0) {
|
||||
globalThis.vm().throwError(globalThis, JSC.toTypeError(
|
||||
JSC.Node.ErrorCode.ERR_MISSING_ARGS,
|
||||
"write() expects a string, ArrayBufferView, or ArrayBuffer",
|
||||
.{},
|
||||
globalThis,
|
||||
);
|
||||
globalThis.vm().throwError(globalThis, err);
|
||||
));
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
|
||||
@@ -2043,6 +2042,16 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
|
||||
arg.ensureStillAlive();
|
||||
defer arg.ensureStillAlive();
|
||||
|
||||
if (arg.isEmptyOrUndefinedOrNull()) {
|
||||
globalThis.vm().throwError(globalThis, JSC.toTypeError(
|
||||
JSC.Node.ErrorCode.ERR_STREAM_NULL_VALUES,
|
||||
"write() expects a string, ArrayBufferView, or ArrayBuffer",
|
||||
.{},
|
||||
globalThis,
|
||||
));
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
|
||||
if (arg.asArrayBuffer(globalThis)) |buffer| {
|
||||
const slice = buffer.slice();
|
||||
if (slice.len == 0) {
|
||||
@@ -2052,6 +2061,16 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
|
||||
return this.sink.writeBytes(.{ .temporary = bun.ByteList.init(slice) }).toJS(globalThis);
|
||||
}
|
||||
|
||||
if (!arg.isString()) {
|
||||
globalThis.vm().throwError(globalThis, JSC.toTypeError(
|
||||
JSC.Node.ErrorCode.ERR_INVALID_ARG_TYPE,
|
||||
"write() expects a string, ArrayBufferView, or ArrayBuffer",
|
||||
.{},
|
||||
globalThis,
|
||||
));
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
|
||||
const str = arg.getZigString(globalThis);
|
||||
if (str.len == 0) {
|
||||
return JSC.JSValue.jsNumber(0);
|
||||
|
||||
@@ -478,7 +478,7 @@ pub const TestCommand = struct {
|
||||
if (reporter.summary.expectations > 0) Output.prettyError(" {d:5>} expect() calls\n", .{reporter.summary.expectations});
|
||||
|
||||
Output.prettyError(
|
||||
\\ Ran {d} tests across {d} files
|
||||
\\ Ran {d} tests across {d} files
|
||||
, .{
|
||||
reporter.summary.fail + reporter.summary.pass,
|
||||
test_files.len,
|
||||
@@ -593,8 +593,8 @@ pub const TestCommand = struct {
|
||||
module.runTests(JSC.JSValue.zero, vm.global);
|
||||
vm.eventLoop().tick();
|
||||
|
||||
const initial_unhandled_counter = vm.unhandled_error_counter;
|
||||
while (vm.active_tasks > 0 and vm.unhandled_error_counter == initial_unhandled_counter) {
|
||||
var prev_unhandled_count = vm.unhandled_error_counter;
|
||||
while (vm.active_tasks > 0) {
|
||||
if (!jest.Jest.runner.?.has_pending_tests) jest.Jest.runner.?.drain();
|
||||
vm.eventLoop().tick();
|
||||
|
||||
@@ -603,6 +603,11 @@ pub const TestCommand = struct {
|
||||
if (!jest.Jest.runner.?.has_pending_tests) break;
|
||||
vm.eventLoop().tick();
|
||||
}
|
||||
|
||||
while (prev_unhandled_count < vm.unhandled_error_counter) {
|
||||
vm.global.handleRejectedPromises();
|
||||
prev_unhandled_count = vm.unhandled_error_counter;
|
||||
}
|
||||
}
|
||||
_ = vm.global.vm().runGC(false);
|
||||
}
|
||||
|
||||
@@ -500,20 +500,20 @@ describe("createWriteStream", () => {
|
||||
const stream = createWriteStream(path);
|
||||
try {
|
||||
stream.write(null);
|
||||
throw new Error("should not get here");
|
||||
expect(() => {}).toThrow(Error);
|
||||
} catch (exception) {
|
||||
expect(exception.code).toBe("ERR_STREAM_NULL_VALUES");
|
||||
}
|
||||
});
|
||||
|
||||
it("writing null with objectMode: true throws ERR_STREAM_NULL_VALUES", async () => {
|
||||
it("writing null throws ERR_STREAM_NULL_VALUES (objectMode: true)", async () => {
|
||||
const path = `/tmp/fs.test.js/${Date.now()}.createWriteStreamNulls.txt`;
|
||||
const stream = createWriteStream(path, {
|
||||
objectMode: true,
|
||||
});
|
||||
try {
|
||||
stream.write(null);
|
||||
throw new Error("should not get here");
|
||||
expect(() => {}).toThrow(Error);
|
||||
} catch (exception) {
|
||||
expect(exception.code).toBe("ERR_STREAM_NULL_VALUES");
|
||||
}
|
||||
@@ -524,26 +524,32 @@ describe("createWriteStream", () => {
|
||||
const stream = createWriteStream(path);
|
||||
try {
|
||||
stream.write(false);
|
||||
throw new Error("should not get here");
|
||||
expect(() => {}).toThrow(Error);
|
||||
} catch (exception) {
|
||||
expect(exception.code).toBe("ERR_INVALID_ARG_TYPE");
|
||||
}
|
||||
});
|
||||
|
||||
it("writing false with objectMode: true should not throw", async () => {
|
||||
it("writing false throws ERR_INVALID_ARG_TYPE (objectMode: true)", async () => {
|
||||
const path = `/tmp/fs.test.js/${Date.now()}.createWriteStreamFalse.txt`;
|
||||
const stream = createWriteStream(path, {
|
||||
objectMode: true,
|
||||
});
|
||||
stream.write(false);
|
||||
stream.on("error", () => {
|
||||
throw new Error("should not get here");
|
||||
});
|
||||
try {
|
||||
stream.write(false);
|
||||
expect(() => {}).toThrow(Error);
|
||||
} catch (exception) {
|
||||
expect(exception.code).toBe("ERR_INVALID_ARG_TYPE");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("fs/promises", () => {
|
||||
const { readFile, writeFile } = promises;
|
||||
const { readFile, stat, writeFile } = promises;
|
||||
|
||||
it("should not segfault on exception", async () => {
|
||||
stat("foo/bar");
|
||||
});
|
||||
|
||||
it("readFile", async () => {
|
||||
const data = await readFile(import.meta.dir + "/readFileSync.txt", "utf8");
|
||||
|
||||
Reference in New Issue
Block a user