aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-04-28 17:46:43 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-04-28 17:46:43 -0700
commit994c715700555fab33e1d73b7ac3d2941e674559 (patch)
tree0ccc7064363345d631f7f9c263b226b8f825242a
parente3a0c4e06d4fb4f0c4d03f85bae45266415d4204 (diff)
downloadbun-994c715700555fab33e1d73b7ac3d2941e674559.tar.gz
bun-994c715700555fab33e1d73b7ac3d2941e674559.tar.zst
bun-994c715700555fab33e1d73b7ac3d2941e674559.zip
Fix race condition
-rw-r--r--.github/scripts/test-runner.ts3
-rw-r--r--src/bundler/bundle_v2.zig49
2 files changed, 50 insertions, 2 deletions
diff --git a/.github/scripts/test-runner.ts b/.github/scripts/test-runner.ts
index 1aaef2b31..a21cc818d 100644
--- a/.github/scripts/test-runner.ts
+++ b/.github/scripts/test-runner.ts
@@ -1,3 +1,6 @@
+// Dear reader
+//
+// The existence of this file is temporary, a hack.
import { join, basename } from "node:path";
import { readdirSync, writeSync, fsyncSync, appendFileSync } from "node:fs";
import { spawn, spawnSync } from "node:child_process";
diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig
index a67ec7c2a..f778f160b 100644
--- a/src/bundler/bundle_v2.zig
+++ b/src/bundler/bundle_v2.zig
@@ -34,6 +34,13 @@
// data structures related to `BSSMap`. This still leaks memory, but not very
// much since it only allocates the first time around.
//
+//
+// In development, it is strongly recommended to use either a debug build of
+// mimalloc or Valgrind to help catch memory issues
+// To use a debug build of mimalloc:
+//
+// make mimalloc-debug
+//
const Bundler = bun.Bundler;
const bun = @import("root").bun;
const from = bun.from;
@@ -305,6 +312,9 @@ pub const BundleV2 = struct {
plugins: ?*JSC.API.JSBundler.Plugin = null,
completion: ?*JSBundleCompletionTask = null,
+ // There is a race condition where an onResolve plugin may schedule a task on the bundle thread before it's parsing task completes
+ resolve_tasks_waiting_for_import_source_index: std.AutoArrayHashMapUnmanaged(Index.Int, BabyList(struct { to_source_index: Index, import_record_index: u32 })) = .{},
+
/// Allocations not tracked by a threadlocal heap
free_list: std.ArrayList(string) = std.ArrayList(string).init(bun.default_allocator),
@@ -1037,6 +1047,11 @@ pub const BundleV2 = struct {
) void {
debug("onLoad: ({d}, {s})", .{ load.source_index.get(), @tagName(load.value) });
defer load.deinit();
+ defer {
+ if (comptime FeatureFlags.help_catch_memory_issues) {
+ this.graph.heap.gc(true);
+ }
+ }
switch (load.value.consume()) {
.no_match => {
@@ -1089,6 +1104,12 @@ pub const BundleV2 = struct {
defer this.graph.resolve_pending -= 1;
debug("onResolve: ({s}:{s}, {s})", .{ resolve.import_record.namespace, resolve.import_record.specifier, @tagName(resolve.value) });
+ defer {
+ if (comptime FeatureFlags.help_catch_memory_issues) {
+ this.graph.heap.gc(true);
+ }
+ }
+
switch (resolve.value.consume()) {
.no_match => {
// If it's a file namespace, we should run it through the resolver like normal.
@@ -1191,8 +1212,23 @@ pub const BundleV2 = struct {
if (out_source_index) |source_index| {
if (resolve.import_record.importer_source_index) |importer| {
- var import_record: *ImportRecord = &this.graph.ast.items(.import_records)[importer].slice()[resolve.import_record.import_record_index];
- import_record.source_index = source_index;
+ var source_import_records = &this.graph.ast.items(.import_records)[importer];
+ if (source_import_records.len <= resolve.import_record.import_record_index) {
+ var entry = this.resolve_tasks_waiting_for_import_source_index.getOrPut(this.graph.allocator, importer) catch unreachable;
+ if (!entry.found_existing) {
+ entry.value_ptr.* = .{};
+ }
+ entry.value_ptr.push(
+ this.graph.allocator,
+ .{
+ .to_source_index = source_index,
+ .import_record_index = resolve.import_record.import_record_index,
+ },
+ ) catch unreachable;
+ } else {
+ var import_record: *ImportRecord = &source_import_records.slice()[resolve.import_record.import_record_index];
+ import_record.source_index = source_index;
+ }
}
}
},
@@ -1592,6 +1628,15 @@ pub const BundleV2 = struct {
}
var import_records = result.ast.import_records.clone(this.graph.allocator) catch unreachable;
+
+ if (this.resolve_tasks_waiting_for_import_source_index.fetchSwapRemove(result.source.index.get())) |pending_entry| {
+ for (pending_entry.value.slice()) |to_assign| {
+ import_records.slice()[to_assign.import_record_index].source_index = to_assign.to_source_index;
+ }
+ var list = pending_entry.value.list();
+ list.deinit(this.graph.allocator);
+ }
+
for (import_records.slice(), 0..) |*record, i| {
if (graph.path_to_source_index_map.get(wyhash(0, record.path.text))) |source_index| {
record.source_index.value = source_index;