Skip to content

Commit 60d64e8

Browse files
committed
Rewrite microsoft#205 to harden the implementation
1 parent 998a151 commit 60d64e8

2 files changed

Lines changed: 68 additions & 26 deletions

File tree

wasm-wasi-core/src/common/buffer.ts

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ export function read(content: Uint8Array, offset: number, buffers: Uint8Array[])
1414
return totalBytesRead;
1515
}
1616

17+
// copied from TS's es2024.arraybuffer.d.ts
18+
interface MaybeResizableArrayBuffer extends ArrayBuffer {
19+
get maxByteLength(): number;
20+
get resizable(): boolean;
21+
resize: (newByteLength?: number) => void;
22+
}
23+
24+
interface ResizableArrayBufferConstructor extends ArrayBufferConstructor {
25+
new (byteLength: number, options?: { maxByteLength?: number; }): MaybeResizableArrayBuffer;
26+
}
27+
28+
declare const ArrayBuffer: ResizableArrayBufferConstructor;
29+
30+
let isArrayBufferResizingSupported: boolean | undefined = undefined;
31+
function canResizeArrayBuffers() {
32+
if (isArrayBufferResizingSupported !== undefined) {
33+
return isArrayBufferResizingSupported;
34+
}
35+
const ab = new ArrayBuffer(1, { maxByteLength: 4 });
36+
return (isArrayBufferResizingSupported = !!ab.resizable);
37+
}
38+
1739
export function write(content: Uint8Array, offset: number, buffers: Uint8Array[]): [Uint8Array, size] {
1840
let bytesToWrite: size = 0;
1941
for (const bytes of buffers) {
@@ -24,22 +46,27 @@ export function write(content: Uint8Array, offset: number, buffers: Uint8Array[]
2446

2547
// Do we need to increase the buffer
2648
if (newSize > content.byteLength) {
27-
interface ResizeableArrayBuffer extends ArrayBuffer {
28-
resize: (newByteLength: number) => void;
29-
maxByteLength: number;
30-
}
31-
//Utilize ECMAScript 2024 In-Place Resizable ArrayBuffers
32-
33-
const buffer = content.buffer as ResizeableArrayBuffer;
34-
const oldSize = buffer.maxByteLength;
35-
36-
if(newSize < oldSize){
37-
buffer.resize(newSize);
38-
} else {
39-
const newBuffer = new (ArrayBuffer as any)(newSize, { maxByteLength: Math.max(newSize, oldSize << 1) });
40-
const newContent = new Uint8Array(newBuffer);
49+
if (!canResizeArrayBuffers()) {
50+
// resizing is unsupported; fallback to always copying over
51+
const newContent = new Uint8Array(offset + bytesToWrite);
4152
newContent.set(content);
4253
content = newContent;
54+
} else {
55+
// Utilize ECMAScript 2024 In-Place Resizable ArrayBuffers
56+
const buffer = content.buffer as MaybeResizableArrayBuffer;
57+
58+
const oldSize = buffer.maxByteLength;
59+
60+
if (newSize < oldSize) {
61+
// content.byteLength < newSize < oldSize = content.buffer.maxByteLength;
62+
// hence the buffer must be resizable
63+
buffer.resize(newSize);
64+
} else if (newSize > oldSize) {
65+
const newBuffer = new ArrayBuffer(newSize, { maxByteLength: Math.max(newSize, oldSize << 1) });
66+
const newContent = new Uint8Array(newBuffer);
67+
newContent.set(content);
68+
content = newContent;
69+
}
4370
}
4471
}
4572

wasm-wasi-core/src/common/test/wasi.worker.test.ts

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -761,23 +761,38 @@ suite(`Filesystem - ${memoryQualifier}`, () => {
761761
test('fd_write - multiple ciovec', () => {
762762
const memory = createMemory();
763763
const filename = `/tmp/${uuid.v4()}`;
764-
const hw = ['Hello ', 'World ', '!!!'];
764+
const hw1 = ['Hello ', 'World ', '!!!'];
765+
const hw2 = ['Hello ', 'World ', ', again', '!!!'];
765766
const fd = FileSystem.createFile(memory, rootFd, filename);
766-
const ciovecs = memory.allocStructArray(3, Ciovec);
767-
let contentLength: number = 0;
768-
for (let i = 0; i < hw.length; i++) {
769-
const content = memory.allocBytes(encoder.encode(hw[i]));
770-
ciovecs.get(i).buf = content.$ptr;
771-
ciovecs.get(i).buf_len = content.byteLength;
772-
contentLength += content.byteLength;
767+
const ciovecs1 = memory.allocStructArray(3, Ciovec);
768+
let contentLength1: number = 0;
769+
for (let i = 0; i < hw1.length; i++) {
770+
const content = memory.allocBytes(encoder.encode(hw1[i]));
771+
ciovecs1.get(i).buf = content.$ptr;
772+
ciovecs1.get(i).buf_len = content.byteLength;
773+
contentLength1 += content.byteLength;
773774
}
775+
const ciovecs2 = memory.allocStructArray(4, Ciovec);
776+
let contentLength2: number = 0;
777+
for (let i = 0; i < hw2.length; i++) {
778+
const content = memory.allocBytes(encoder.encode(hw2[i]));
779+
ciovecs2.get(i).buf = content.$ptr;
780+
ciovecs2.get(i).buf_len = content.byteLength;
781+
contentLength2 += content.byteLength;
782+
}
783+
774784
const bytesWritten = memory.allocUint32();
775-
let errno = wasi.fd_write(fd, ciovecs.$ptr, ciovecs.size, bytesWritten.$ptr);
785+
let errno1 = wasi.fd_write(fd, ciovecs1.$ptr, ciovecs1.size, bytesWritten.$ptr);
786+
assert.strictEqual(errno1, Errno.success);
787+
assert.strictEqual(bytesWritten.value, contentLength1);
788+
789+
let errno2 = wasi.fd_write(fd, ciovecs2.$ptr, ciovecs2.size, bytesWritten.$ptr);
790+
assert.strictEqual(errno2, Errno.success);
791+
assert.strictEqual(bytesWritten.value, contentLength2);
776792
FileSystem.close(fd);
793+
777794
const check = FileSystem.openFile(memory, rootFd, filename);
778-
assert.strictEqual(errno, Errno.success);
779-
assert.strictEqual(bytesWritten.value, contentLength);
780-
assert.strictEqual(decoder.decode(FileSystem.read(memory, check)), hw.join(''));
795+
assert.strictEqual(decoder.decode(FileSystem.read(memory, check)), hw1.join('') + hw2.join(''));
781796
FileSystem.close(check);
782797
});
783798

0 commit comments

Comments
 (0)