deno icon indicating copy to clipboard operation
deno copied to clipboard

Incorrect type checking of objects throughout JS codebase

Open vimirage opened this issue 3 years ago • 2 comments

Example:

const buffer = new ArrayBuffer(100);
// remove prototype
Reflect.setPrototypeOf(buffer, null);
structuredClone(buffer, { transfer: [buffer] });
// restore prototype
Reflect.setPrototypeOf(buffer, ArrayBuffer.prototype);
// assert that {structuredClone} transferred the buffer
console.log(0 === buffer.byteLength);

This throws in Deno as of 1.24.0, but not the browsers, or Node.js. A TypeError occurs under the belief that, as the object does not have the ArrayBuffer prototype, it is not transferable. Caused by the use of Object#isPrototypeOf. (V8 and the BlinkIDL bindgen do not use prototypes for checking object types)

vimirage avatar Jul 27 '22 07:07 vimirage

In fact, the transfer field is typed as sequence<object> in WebIDL, and the actual type checking happens as part of the structured clone algorithm, not on the WebIDL layer. But IIRC Deno first splits buffers from MessagePort objects in the transferable list (since those are the only two types of transferable that we currently support), and that happens on the JS side, so the checking is done based on the prototypes.

This might be solved with my work on reworking serialization and transferring (#12067), but that has been stuck for a while.

andreubotella avatar Jul 27 '22 07:07 andreubotella

In fact, the transfer field is typed as sequence<object> in WebIDL, and the actual type checking happens as part of the structured clone algorithm, not on the WebIDL layer. But IIRC Deno first splits buffers from MessagePort objects in the transferable list (since those are the only two types of transferable that we currently support), and that happens on the JS side, so the checking is done based on the prototypes.

This might be solved with my work on reworking serialization and transferring (#12067), but that has been stuck for a while.

Nonetheless, outside of this particular example, the isPrototypeOf can be used to cause similar issues anywhere. (webidl.createInterfaceConverter is merely a prototype check.) Although, does that PR intend to rewrite even non-transferable objects are host/platform object, and use something more akin to Chromium's nominal type checking? If not, the issue persists in the rest of the codebase.

vimirage avatar Jul 27 '22 08:07 vimirage

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Sep 27 '22 17:09 stale[bot]

shoo, stale bot

vimirage avatar Oct 03 '22 06:10 vimirage