mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-10-28 08:36:17 +08:00
webapi: reject writes to detached buffers in WebCodecs
This commit is contained in:
4 files changed
+52
-2
No files matched your search
@@ -87,3 +87,27 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=copy_to_detached_destination>
|
||||
{
|
||||
// An options getter that detaches the destination must not cause a write
|
||||
// into the freed backing store: copyTo re-reads the destination after the
|
||||
// options are coerced, so a detached buffer fails the bounds check instead.
|
||||
const src = new AudioData({
|
||||
format: 'u8', sampleRate: 8000, numberOfFrames: 8,
|
||||
numberOfChannels: 1, timestamp: 0, data: new Uint8Array(8),
|
||||
});
|
||||
const dest = new Uint8Array(8);
|
||||
let threw = false;
|
||||
try {
|
||||
src.copyTo(dest, {
|
||||
planeIndex: 0,
|
||||
get frameOffset() { dest.buffer.transfer(0); return 0; },
|
||||
});
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
testing.expectEqual(true, threw);
|
||||
testing.expectEqual(0, dest.byteLength);
|
||||
}
|
||||
</script>
|
||||
@@ -143,3 +143,24 @@
|
||||
testing.expectError('InvalidStateError', () => new VideoFrame(new OffscreenCanvas(32767, 32767), {timestamp: 1}));
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=copy_to_detached_destination type=module>
|
||||
const state = await testing.async();
|
||||
// An options getter that detaches the destination must not cause a write
|
||||
// into the freed backing store: copyTo re-reads the destination after the
|
||||
// options are coerced, so a detached buffer rejects instead.
|
||||
const frame = new VideoFrame(new Uint8Array([1, 2, 3, 4]), {format: 'RGBA', timestamp: 0, codedWidth: 1, codedHeight: 1});
|
||||
const dest = new Uint8Array(4);
|
||||
let error = null;
|
||||
try {
|
||||
await frame.copyTo(dest, {get rect() { dest.buffer.transfer(0); return undefined; }});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
state.resolve();
|
||||
await state.done(() => {
|
||||
testing.expectEqual(true, error !== null);
|
||||
testing.expectEqual(0, dest.byteLength);
|
||||
});
|
||||
</script>
|
||||
@@ -259,7 +259,9 @@ fn allocationSize(self: *const AudioData, options: CopyToOptions) !u32 {
|
||||
return std.math.cast(u32, copy.byteLength()) orelse error.RangeError;
|
||||
}
|
||||
|
||||
fn copyTo(self: *const AudioData, destination: js.AllowSharedBufferSource, options: CopyToOptions) !void {
|
||||
fn copyTo(self: *const AudioData, destination_value: js.Value, options: CopyToOptions, exec: *const Execution) !void {
|
||||
const destination = try exec.js.local.?.jsValueToZig(js.AllowSharedBufferSource, destination_value);
|
||||
|
||||
const copy = try self.computeCopy(options);
|
||||
const byte_length = copy.byteLength();
|
||||
if (byte_length > destination.bytes.len) {
|
||||
|
||||
@@ -745,8 +745,11 @@ fn allocationSize(self: *const VideoFrame, options_: ?CopyToOptions) !u32 {
|
||||
return parsed.layout.allocation_size;
|
||||
}
|
||||
|
||||
fn copyTo(self: *const VideoFrame, destination: js.AllowSharedBufferSource, options_: ?CopyToOptions, exec: *const Execution) !js.Promise {
|
||||
fn copyTo(self: *const VideoFrame, destination_value: js.Value, options_: ?CopyToOptions, exec: *const Execution) !js.Promise {
|
||||
const local = exec.js.local.?;
|
||||
const destination = local.jsValueToZig(js.AllowSharedBufferSource, destination_value) catch {
|
||||
return local.rejectPromise(.{ .type_error = "" });
|
||||
};
|
||||
const layouts = self.copyInto(destination.bytes, options_ orelse .{}) catch |err| {
|
||||
return local.rejectPromise(switch (err) {
|
||||
error.TypeError => .{ .type_error = "" },
|
||||
|
||||
Reference in new issue
Block a user