Skip to content

Commit d2cdb50

Browse files
Fix potential crash when printing errors in bun install (#17027)
1 parent 0c8658b commit d2cdb50

File tree

1 file changed

+35
-30
lines changed

1 file changed

+35
-30
lines changed

src/install/install.zig

+35-30
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ pub const Aligner = struct {
255255
};
256256

257257
const NetworkTask = struct {
258-
http: AsyncHTTP = undefined,
258+
unsafe_http_client: AsyncHTTP = undefined,
259+
response: bun.http.HTTPClientResult = .{},
259260
task_id: u64,
260261
url_buf: []const u8 = &[_]u8{},
261262
retried: u16 = 0,
@@ -282,10 +283,11 @@ const NetworkTask = struct {
282283
};
283284
pub const DedupeMap = std.HashMap(u64, DedupeMapEntry, IdentityContext(u64), 80);
284285

285-
pub fn notify(this: *NetworkTask, async_http: *AsyncHTTP, _: anytype) void {
286+
pub fn notify(this: *NetworkTask, async_http: *AsyncHTTP, result: bun.http.HTTPClientResult) void {
286287
defer this.package_manager.wake();
287288
async_http.real.?.* = async_http.*;
288289
async_http.real.?.response_buffer = async_http.response_buffer;
290+
this.response = result;
289291
this.package_manager.async_network_task_queue.push(this);
290292
}
291293

@@ -454,13 +456,13 @@ const NetworkTask = struct {
454456
this.allocator = allocator;
455457

456458
const url = URL.parse(this.url_buf);
457-
this.http = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_builder.content.ptr.?[0..header_builder.content.len], &this.response_buffer, "", this.getCompletionCallback(), HTTP.FetchRedirect.follow, .{
459+
this.unsafe_http_client = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_builder.content.ptr.?[0..header_builder.content.len], &this.response_buffer, "", this.getCompletionCallback(), HTTP.FetchRedirect.follow, .{
458460
.http_proxy = this.package_manager.httpProxy(url),
459461
});
460-
this.http.client.flags.reject_unauthorized = this.package_manager.tlsRejectUnauthorized();
462+
this.unsafe_http_client.client.flags.reject_unauthorized = this.package_manager.tlsRejectUnauthorized();
461463

462464
if (PackageManager.verbose_install) {
463-
this.http.client.verbose = .headers;
465+
this.unsafe_http_client.client.verbose = .headers;
464466
}
465467

466468
this.callback = .{
@@ -471,14 +473,14 @@ const NetworkTask = struct {
471473
};
472474

473475
if (PackageManager.verbose_install) {
474-
this.http.verbose = .headers;
475-
this.http.client.verbose = .headers;
476+
this.unsafe_http_client.verbose = .headers;
477+
this.unsafe_http_client.client.verbose = .headers;
476478
}
477479

478480
// Incase the ETag causes invalidation, we fallback to the last modified date.
479481
if (last_modified.len != 0 and bun.getRuntimeFeatureFlag("BUN_FEATURE_FLAG_LAST_MODIFIED_PRETEND_304")) {
480-
this.http.client.flags.force_last_modified = true;
481-
this.http.client.if_modified_since = last_modified;
482+
this.unsafe_http_client.client.flags.force_last_modified = true;
483+
this.unsafe_http_client.client.if_modified_since = last_modified;
482484
}
483485
}
484486

@@ -487,7 +489,7 @@ const NetworkTask = struct {
487489
}
488490

489491
pub fn schedule(this: *NetworkTask, batch: *ThreadPool.Batch) void {
490-
this.http.schedule(this.allocator, batch);
492+
this.unsafe_http_client.schedule(this.allocator, batch);
491493
}
492494

493495
pub const ForTarballError = OOM || error{
@@ -547,12 +549,12 @@ const NetworkTask = struct {
547549

548550
const url = URL.parse(this.url_buf);
549551

550-
this.http = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_buf, &this.response_buffer, "", this.getCompletionCallback(), HTTP.FetchRedirect.follow, .{
552+
this.unsafe_http_client = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_buf, &this.response_buffer, "", this.getCompletionCallback(), HTTP.FetchRedirect.follow, .{
551553
.http_proxy = this.package_manager.httpProxy(url),
552554
});
553-
this.http.client.flags.reject_unauthorized = this.package_manager.tlsRejectUnauthorized();
555+
this.unsafe_http_client.client.flags.reject_unauthorized = this.package_manager.tlsRejectUnauthorized();
554556
if (PackageManager.verbose_install) {
555-
this.http.client.verbose = .headers;
557+
this.unsafe_http_client.client.verbose = .headers;
556558
}
557559
}
558560
};
@@ -736,7 +738,7 @@ pub const Task = struct {
736738
const package_manifest = Npm.Registry.getPackageMetadata(
737739
allocator,
738740
manager.scopeForPackageName(manifest.name.slice()),
739-
manifest.network.http.response.?,
741+
(manifest.network.response.metadata orelse @panic("Assertion failure: Expected metadata to be set")).response,
740742
body,
741743
&this.log,
742744
manifest.name.slice(),
@@ -6402,7 +6404,7 @@ pub const PackageManager = struct {
64026404
}
64036405
}
64046406

6405-
if (!has_network_error and task.http.response == null) {
6407+
if (!has_network_error and task.response.metadata == null) {
64066408
has_network_error = true;
64076409
const min = manager.options.min_simultaneous_requests;
64086410
const max = AsyncHTTP.max_simultaneous_requests.load(.monotonic);
@@ -6412,8 +6414,8 @@ pub const PackageManager = struct {
64126414
}
64136415

64146416
// Handle retry-able errors.
6415-
if (task.http.response == null or task.http.response.?.status_code > 499) {
6416-
const err = task.http.err orelse error.HTTPError;
6417+
if (task.response.metadata == null or task.response.metadata.?.response.status_code > 499) {
6418+
const err = task.response.fail orelse error.HTTPError;
64176419

64186420
if (task.retried < manager.options.max_retry_count) {
64196421
task.retried += 1;
@@ -6433,9 +6435,9 @@ pub const PackageManager = struct {
64336435
}
64346436
}
64356437

6436-
const response = task.http.response orelse {
6438+
const metadata = task.response.metadata orelse {
64376439
// Handle non-retry-able errors.
6438-
const err = task.http.err orelse error.HTTPError;
6440+
const err = task.response.fail orelse error.HTTPError;
64396441

64406442
if (@TypeOf(callbacks.onPackageManifestError) != void) {
64416443
callbacks.onPackageManifestError(
@@ -6478,6 +6480,7 @@ pub const PackageManager = struct {
64786480

64796481
continue;
64806482
};
6483+
const response = metadata.response;
64816484

64826485
if (response.status_code > 399) {
64836486
if (@TypeOf(callbacks.onPackageManifestError) != void) {
@@ -6507,15 +6510,15 @@ pub const PackageManager = struct {
65076510
logger.Loc.Empty,
65086511
manager.allocator,
65096512
"<r><red><b>GET<r><red> {s}<d> - {d}<r>",
6510-
.{ task.http.client.url.href, response.status_code },
6513+
.{ metadata.url, response.status_code },
65116514
) catch bun.outOfMemory();
65126515
} else {
65136516
manager.log.addWarningFmt(
65146517
null,
65156518
logger.Loc.Empty,
65166519
manager.allocator,
65176520
"<r><yellow><b>GET<r><yellow> {s}<d> - {d}<r>",
6518-
.{ task.http.client.url.href, response.status_code },
6521+
.{ metadata.url, response.status_code },
65196522
) catch bun.outOfMemory();
65206523
}
65216524
if (manager.subcommand != .remove) {
@@ -6534,7 +6537,7 @@ pub const PackageManager = struct {
65346537

65356538
if (comptime log_level.isVerbose()) {
65366539
Output.prettyError(" ", .{});
6537-
Output.printElapsed(@as(f64, @floatFromInt(task.http.elapsed)) / std.time.ns_per_ms);
6540+
Output.printElapsed(@as(f64, @floatFromInt(task.unsafe_http_client.elapsed)) / std.time.ns_per_ms);
65386541
Output.prettyError("\n<d>Downloaded <r><green>{s}<r> versions\n", .{name.slice()});
65396542
Output.flush();
65406543
}
@@ -6582,7 +6585,7 @@ pub const PackageManager = struct {
65826585
manager.task_batch.push(ThreadPool.Batch.from(manager.enqueueParseNPMPackage(task.task_id, name, task)));
65836586
},
65846587
.extract => |*extract| {
6585-
if (!has_network_error and task.http.response == null) {
6588+
if (!has_network_error and task.response.metadata == null) {
65866589
has_network_error = true;
65876590
const min = manager.options.min_simultaneous_requests;
65886591
const max = AsyncHTTP.max_simultaneous_requests.load(.monotonic);
@@ -6591,8 +6594,8 @@ pub const PackageManager = struct {
65916594
}
65926595
}
65936596

6594-
if (task.http.response == null or task.http.response.?.status_code > 499) {
6595-
const err = task.http.err orelse error.TarballFailedToDownload;
6597+
if (task.response.metadata == null or task.response.metadata.?.response.status_code > 499) {
6598+
const err = task.response.fail orelse error.TarballFailedToDownload;
65966599

65976600
if (task.retried < manager.options.max_retry_count) {
65986601
task.retried += 1;
@@ -6618,8 +6621,8 @@ pub const PackageManager = struct {
66186621
}
66196622
}
66206623

6621-
const response = task.http.response orelse {
6622-
const err = task.http.err orelse error.TarballFailedToDownload;
6624+
const metadata = task.response.metadata orelse {
6625+
const err = task.response.fail orelse error.TarballFailedToDownload;
66236626

66246627
if (@TypeOf(callbacks.onPackageDownloadError) != void) {
66256628
const package_id = manager.lockfile.buffers.resolutions.items[extract.dependency_id];
@@ -6674,6 +6677,8 @@ pub const PackageManager = struct {
66746677
continue;
66756678
};
66766679

6680+
const response = metadata.response;
6681+
66776682
if (response.status_code > 399) {
66786683
if (@TypeOf(callbacks.onPackageDownloadError) != void) {
66796684
const err = switch (response.status_code) {
@@ -6705,7 +6710,7 @@ pub const PackageManager = struct {
67056710
manager.allocator,
67066711
"<r><red><b>GET<r><red> {s}<d> - {d}<r>",
67076712
.{
6708-
task.http.client.url.href,
6713+
metadata.url,
67096714
response.status_code,
67106715
},
67116716
) catch bun.outOfMemory();
@@ -6716,7 +6721,7 @@ pub const PackageManager = struct {
67166721
manager.allocator,
67176722
"<r><yellow><b>GET<r><yellow> {s}<d> - {d}<r>",
67186723
.{
6719-
task.http.client.url.href,
6724+
metadata.url,
67206725
response.status_code,
67216726
},
67226727
) catch bun.outOfMemory();
@@ -6737,7 +6742,7 @@ pub const PackageManager = struct {
67376742

67386743
if (comptime log_level.isVerbose()) {
67396744
Output.prettyError(" ", .{});
6740-
Output.printElapsed(@as(f64, @floatCast(@as(f64, @floatFromInt(task.http.elapsed)) / std.time.ns_per_ms)));
6745+
Output.printElapsed(@as(f64, @floatCast(@as(f64, @floatFromInt(task.unsafe_http_client.elapsed)) / std.time.ns_per_ms)));
67416746
Output.prettyError("<d> Downloaded <r><green>{s}<r> tarball\n", .{extract.name.slice()});
67426747
Output.flush();
67436748
}

0 commit comments

Comments
 (0)