diff --git a/packages/ses/NEWS.md b/packages/ses/NEWS.md index 921175873d..f9cae30c05 100644 --- a/packages/ses/NEWS.md +++ b/packages/ses/NEWS.md @@ -2,6 +2,12 @@ User-visible changes in `ses`: # Next release +- Uses the `@endo/immutable-arraybuffer` shim to add `ArrayBuffer.p.immutable`, `ArrayBuffer.p.transferToImmutable`, and `ArrayBuffer.p.sliceToImmutable` to ses, in order to emulate the [Immutable ArrayBuffer proposal](https://github.com/tc39/proposal-immutable-arraybuffer). These make an ArrayBuffer-like object whose contents cannot be mutated. However, due to limitations of the shim + - Unlike `ArrayBuffer` and `SharedArrayBuffer` this shim's ArrayBuffer-like object cannot be transfered or cloned between JS threads. + - Unlike `ArrayBuffer` and `SharedArrayBuffer`, this shim's ArrayBuffer-like object cannot be used as the backing store of TypeArrays or DataViews. + - The shim depends on the platform providing either `structuredClone` or `Array.prototype.transfer`. Node <= 16 provides neither, causing the shim to fail to initialize, and therefore SES to fail to initialize on such platforms. + - Even after the upcoming `transferToImmutable` proposal is implemented by the platform, the current code will still replace it with the shim implementation, in accord with shim best practices. See https://github.com/endojs/endo/pull/2311#discussion_r1632607527 . It will require a later manual step to delete the shim, after manual analysis of the compat implications. + - Adds support for dynamic `import` in conjunction with an update to `@endo/module-source`. diff --git a/packages/ses/package.json b/packages/ses/package.json index e552bda739..fe40a44d41 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -85,7 +85,8 @@ "postpack": "git clean -f '*.d.ts*' '*.tsbuildinfo'" }, "dependencies": { - "@endo/env-options": "workspace:^" + "@endo/env-options": "workspace:^", + "@endo/immutable-arraybuffer": "workspace:^" }, "devDependencies": { "@endo/compartment-mapper": "workspace:^", diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index f7fcd37118..8f2a0cefe0 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -14,6 +14,7 @@ import { matchAllSymbol, regexpPrototype, globalThis, + ArrayBuffer, } from './commons.js'; import { InertCompartment } from './compartment.js'; @@ -161,5 +162,15 @@ export const getAnonymousIntrinsics = () => { ); } + const ab = new ArrayBuffer(0); + // @ts-expect-error TODO How do I add transferToImmutable to ArrayBuffer type? + // eslint-disable-next-line @endo/no-polymorphic-call + const iab = ab.transferToImmutable(); + const iabProto = getPrototypeOf(iab); + if (iabProto !== ArrayBuffer.prototype) { + // In a native implementation, these will be the same prototype + intrinsics['%ImmutableArrayBufferPrototype%'] = iabProto; + } + return intrinsics; }; diff --git a/packages/ses/src/lockdown.js b/packages/ses/src/lockdown.js index d55e8b2ebf..237fe967d4 100644 --- a/packages/ses/src/lockdown.js +++ b/packages/ses/src/lockdown.js @@ -15,6 +15,7 @@ // @ts-check import { getEnvironmentOption as getenv } from '@endo/env-options'; +import '@endo/immutable-arraybuffer/shim.js'; import { FERAL_FUNCTION, FERAL_EVAL, diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index 283d861c34..2c943cb515 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1305,6 +1305,33 @@ export const permitted = { // https://github.com/tc39/proposal-arraybuffer-transfer transferToFixedLength: fn, detached: getter, + // https://github.com/endojs/endo/pull/2309#issuecomment-2155513240 + // to be proposed + transferToImmutable: fn, + sliceToImmutable: fn, + immutable: getter, + }, + + // If this exists, it is purely an artifact of how we currently shim + // `transferToImmutable`. As natively implemented, there would be no + // such extra prototype. + '%ImmutableArrayBufferPrototype%': { + '[[Proto]]': '%ArrayBufferPrototype%', + byteLength: getter, + slice: fn, + // See https://github.com/tc39/proposal-resizablearraybuffer + transfer: fn, + resize: fn, + resizable: getter, + maxByteLength: getter, + // https://github.com/tc39/proposal-arraybuffer-transfer + transferToFixedLength: fn, + detached: getter, + // https://github.com/endojs/endo/pull/2309#issuecomment-2155513240 + // to be proposed + transferToImmutable: fn, + sliceToImmutable: fn, + immutable: getter, }, // SharedArrayBuffer Objects diff --git a/packages/ses/test/immutable-array-buffer.test.js b/packages/ses/test/immutable-array-buffer.test.js new file mode 100644 index 0000000000..9e422589cb --- /dev/null +++ b/packages/ses/test/immutable-array-buffer.test.js @@ -0,0 +1,14 @@ +import test from 'ava'; +import '../index.js'; + +const { isFrozen, getPrototypeOf } = Object; + +lockdown(); + +test('ses Immutable ArrayBuffer shim installed and hardened', t => { + const ab1 = new ArrayBuffer(0); + const iab = ab1.transferToImmutable(); + const iabProto = getPrototypeOf(iab); + t.true(isFrozen(iabProto)); + t.true(isFrozen(iabProto.slice)); +}); diff --git a/yarn.lock b/yarn.lock index a838a69480..4ddd432e29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -524,7 +524,7 @@ __metadata: languageName: unknown linkType: soft -"@endo/immutable-arraybuffer@workspace:packages/immutable-arraybuffer": +"@endo/immutable-arraybuffer@workspace:^, @endo/immutable-arraybuffer@workspace:packages/immutable-arraybuffer": version: 0.0.0-use.local resolution: "@endo/immutable-arraybuffer@workspace:packages/immutable-arraybuffer" dependencies: @@ -8948,6 +8948,7 @@ __metadata: dependencies: "@endo/compartment-mapper": "workspace:^" "@endo/env-options": "workspace:^" + "@endo/immutable-arraybuffer": "workspace:^" "@endo/module-source": "workspace:^" "@endo/test262-runner": "workspace:^" ava: "npm:^6.1.3"