aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar IAS <93499805+I-A-S@users.noreply.github.com> 2023-10-31 01:06:38 +0530
committerGravatar GitHub <noreply@github.com> 2023-10-30 12:36:38 -0700
commitcbc5ca770bd427ffff29c748f9da60b83b621a00 (patch)
treee5ccfe3dc64b7563871391006f3bb316682363f8
parent2972cfadfb7904d6e0e13f586ffc13bac784e52b (diff)
downloadbun-cbc5ca770bd427ffff29c748f9da60b83b621a00.tar.gz
bun-cbc5ca770bd427ffff29c748f9da60b83b621a00.tar.zst
bun-cbc5ca770bd427ffff29c748f9da60b83b621a00.zip
fix: Macro segmentation faults (#6756)
* Fix for seg faults when using macros * Update src/js_ast.zig to reflect review suggestions Co-authored-by: Jarred Sumner <jarred@jarredsumner.com> * add test for checking non-zero exitcodes under macros. regression, issue 3830 --------- Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
-rw-r--r--src/js_ast.zig15
-rw-r--r--src/js_parser.zig2
-rw-r--r--test/regression/issue/03830.test.ts30
3 files changed, 42 insertions, 5 deletions
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 3b17240c0..8b745742b 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -7278,8 +7278,9 @@ pub const Macro = struct {
exception_holder = Zig.ZigException.Holder.init();
var js_args: []JSC.JSValue = &.{};
+ var js_processed_args_len: usize = 0;
defer {
- for (js_args[0 .. js_args.len - @as(usize, @intFromBool(!javascript_object.isEmpty()))]) |arg| {
+ for (js_args[0..js_processed_args_len -| @as(usize, @intFromBool(!javascript_object.isEmpty()))]) |arg| {
arg.unprotect();
}
@@ -7292,12 +7293,18 @@ pub const Macro = struct {
.e_call => |call| {
const call_args: []Expr = call.args.slice();
js_args = try allocator.alloc(JSC.JSValue, call_args.len + @as(usize, @intFromBool(!javascript_object.isEmpty())));
+ js_processed_args_len = js_args.len;
- for (call_args, js_args[0..call_args.len]) |in, *out| {
- const value = try in.toJS(
+ for (0.., call_args, js_args[0..call_args.len]) |i, in, *out| {
+ const value = in.toJS(
allocator,
globalObject,
- );
+ ) catch |e| {
+ // Keeping a separate variable instead of modifying js_args.len
+ // due to allocator.free call in defer
+ js_processed_args_len = i;
+ return e;
+ };
value.protect();
out.* = value;
}
diff --git a/src/js_parser.zig b/src/js_parser.zig
index fce928a6e..f569f515f 100644
--- a/src/js_parser.zig
+++ b/src/js_parser.zig
@@ -16389,7 +16389,7 @@ fn NewParser_(
p.log.addError(p.source, expr.loc, "macro threw exception") catch unreachable;
}
} else {
- p.log.addErrorFmt(p.source, expr.loc, p.allocator, "{s} error in macro", .{@errorName(err)}) catch unreachable;
+ p.log.addErrorFmt(p.source, expr.loc, p.allocator, "\"{s}\" error in macro", .{@errorName(err)}) catch unreachable;
}
return expr;
};
diff --git a/test/regression/issue/03830.test.ts b/test/regression/issue/03830.test.ts
new file mode 100644
index 000000000..e0689474c
--- /dev/null
+++ b/test/regression/issue/03830.test.ts
@@ -0,0 +1,30 @@
+// test/regression/issue/03830.test.ts
+
+import { it, expect } from "bun:test";
+import { bunEnv, bunExe } from "harness";
+import { mkdirSync, rmSync, writeFileSync, readFileSync, mkdtempSync } from "fs";
+import { tmpdir } from "os";
+import { join } from "path";
+
+it("macros should not lead to seg faults under any given input", async () => {
+ // this test code follows the same structure as and
+ // is based on the code for testing issue 4893
+
+ const testDir = mkdtempSync(join(tmpdir(), "issue3830-"));
+
+ // Clean up from prior runs if necessary
+ rmSync(testDir, { recursive: true, force: true });
+
+ // Create a directory with our test file
+ mkdirSync(testDir, { recursive: true });
+ writeFileSync(join(testDir, "macro.ts"), 'export function fn(str) { return str; }');
+ writeFileSync(join(testDir, "index.ts"), "import { fn } from './macro' assert { type: 'macro' };\nfn(`©${''}`);");
+
+ const { stdout, exitCode } = Bun.spawnSync({
+ cmd: [bunExe(), "build", join(testDir, "index.ts")],
+ env: bunEnv,
+ stderr: "inherit",
+ });
+
+ expect(exitCode).toBe(0);
+}); \ No newline at end of file