Fix double-free of XHR on double client abort

It's possible (in fact normal) for client.abort to be called twice on a schedule
navigation. We immediately abort any pending requests once a secondary
navigation is called (is that right?), and then again when the page shuts down.

The first abort will kill the transfer, so the XHR object has to null this value
so that, on context shutdown, when the finalizer is called, we don't try to
free it again.
This commit is contained in:
Karl Seguin
2026-02-10 11:30:10 +08:00
parent 60d8f2323e
commit a6ba801738
2 changed files with 8 additions and 1 deletions

View File

@@ -233,6 +233,7 @@ pub fn send(self: *XMLHttpRequest, body_: ?[]const u8) !void {
.data_callback = httpDataCallback,
.done_callback = httpDoneCallback,
.error_callback = httpErrorCallback,
.shutdown_callback = httpShutdownCallback,
});
page.js.strongRef(self);
@@ -463,6 +464,11 @@ fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void {
self._page.js.weakRef(self);
}
fn httpShutdownCallback(ctx: *anyopaque) void {
const self: *XMLHttpRequest = @ptrCast(@alignCast(ctx));
self._transfer = null;
}
pub fn abort(self: *XMLHttpRequest) void {
self.handleError(error.Abort);
if (self._transfer) |transfer| {

View File

@@ -39,9 +39,10 @@ pub const FetchOpts = struct {
writer: ?*std.Io.Writer = null,
};
pub fn fetch(app: *App, url: [:0]const u8, opts: FetchOpts) !void {
var browser = try Browser.init(app, .{});
const notification = try Notification.init(app.allocator);
defer notification.deinit();
var browser = try Browser.init(app, .{});
defer browser.deinit();
var session = try browser.newSession(notification);