fix(ses): removeUnpermittedIntrinsics on Hermes#2655
Conversation
d12c2aa to
d400b04
Compare
There was a problem hiding this comment.
Let's first solve the mystery of why some functions look like sloppy functions. If we cannot make these functions themselves strict, then the right thing for cauterize to do, or perhaps even an earlier repair phase, it to replace these functions with strict wrappers that forward to the original functions.
| if ( | ||
| typeof obj === 'function' && | ||
| (prop === 'caller' || prop === 'arguments') | ||
| ) { | ||
| warn(`Tolerating undeletable ${subPath}`); | ||
| return; | ||
| } |
There was a problem hiding this comment.
But you first need to cauterize them, like I do with .prototype. In this case, you'd also
- set them to undefined
- make them non-writable non-configurable data properties
- check the sloppy mode cases where these properties would change their value to verify that Hermes obeys the non-writable, non-configurable data property stability restriction.
But it's likely worse than that. These properties are symptomatic of these function being defined as sloppy functions, which we simply need to prohibit all access to. Builtin functions are supposed to act like strict functions, including the absence of .caller and .argument properties. On what functions are you seeing these properties? What is different about how they are defined?
There was a problem hiding this comment.
But it's likely worse than that.
very much so 😅
On what functions are you seeing these properties?
the functions in the output after list (in description), i've dug thru the list more thoroughly spotting it's .caller, .arguments and .prototype still, here's the breakdown
output after (detailed)
Promise .caller
Removing intrinsics.Promise.caller
Tolerating undeletable intrinsics.Promise.caller
Removing intrinsics.Promise.arguments
Tolerating undeletable intrinsics.Promise.arguments
Removing intrinsics.Promise._l
Removing intrinsics.Promise._m
Removing intrinsics.Promise._n
Promise .resolve
Removing intrinsics.Promise.resolve.caller
Tolerating undeletable intrinsics.Promise.resolve.caller
Removing intrinsics.Promise.resolve.arguments
Tolerating undeletable intrinsics.Promise.resolve.arguments
Removing intrinsics.Promise.resolve.prototype
Tolerating undeletable intrinsics.Promise.resolve.prototype === undefined
Promise .all
Removing intrinsics.Promise.all.caller
Tolerating undeletable intrinsics.Promise.all.caller
Removing intrinsics.Promise.all.arguments
Tolerating undeletable intrinsics.Promise.all.arguments
Removing intrinsics.Promise.all.prototype
Tolerating undeletable intrinsics.Promise.all.prototype === undefined
Promise .reject
Removing intrinsics.Promise.reject.caller
Tolerating undeletable intrinsics.Promise.reject.caller
Removing intrinsics.Promise.reject.arguments
Tolerating undeletable intrinsics.Promise.reject.arguments
Removing intrinsics.Promise.reject.prototype
Tolerating undeletable intrinsics.Promise.reject.prototype === undefined
Promise .race
Removing intrinsics.Promise.race.caller
Tolerating undeletable intrinsics.Promise.race.caller
Removing intrinsics.Promise.race.arguments
Tolerating undeletable intrinsics.Promise.race.arguments
Removing intrinsics.Promise.race.prototype
Tolerating undeletable intrinsics.Promise.race.prototype === undefined
lockdown
Removing intrinsics.lockdown.caller
Tolerating undeletable intrinsics.lockdown.caller
Removing intrinsics.lockdown.arguments
Tolerating undeletable intrinsics.lockdown.arguments
Removing intrinsics.lockdown.prototype
Tolerating undeletable intrinsics.lockdown.prototype === undefined
harden
Removing intrinsics.harden.caller
Tolerating undeletable intrinsics.harden.caller
Removing intrinsics.harden.arguments
Tolerating undeletable intrinsics.harden.arguments
Removing intrinsics.harden.prototype
Tolerating undeletable intrinsics.harden.prototype === undefined
% Inert Function
Removing intrinsics.%InertFunction%.caller
Tolerating undeletable intrinsics.%InertFunction%.caller
Removing intrinsics.%InertFunction%.arguments
Tolerating undeletable intrinsics.%InertFunction%.arguments
% Inert Generator Function
Removing intrinsics.%InertGeneratorFunction%.caller
Tolerating undeletable intrinsics.%InertGeneratorFunction%.caller
Removing intrinsics.%InertGeneratorFunction%.arguments
Tolerating undeletable intrinsics.%InertGeneratorFunction%.arguments
% Inert Async Function
Removing intrinsics.%InertAsyncFunction%.caller
Tolerating undeletable intrinsics.%InertAsyncFunction%.caller
Removing intrinsics.%InertAsyncFunction%.arguments
Tolerating undeletable intrinsics.%InertAsyncFunction%.arguments
% Initial Date
Removing intrinsics.%InitialDate%.caller
Tolerating undeletable intrinsics.%InitialDate%.caller
Removing intrinsics.%InitialDate%.arguments
Tolerating undeletable intrinsics.%InitialDate%.arguments
% Shared Date
Removing intrinsics.%SharedDate%.caller
Tolerating undeletable intrinsics.%SharedDate%.caller
Removing intrinsics.%SharedDate%.arguments
Tolerating undeletable intrinsics.%SharedDate%.arguments
Removing intrinsics.%SharedDate%.now.caller
Tolerating undeletable intrinsics.%SharedDate%.now.caller
Removing intrinsics.%SharedDate%.now.arguments
Tolerating undeletable intrinsics.%SharedDate%.now.arguments
Removing intrinsics.%SharedDate%.now.prototype
Tolerating undeletable intrinsics.%SharedDate%.now.prototype === undefined
% Initial GetStackString
Removing intrinsics.%InitialGetStackString%.caller
Tolerating undeletable intrinsics.%InitialGetStackString%.caller
Removing intrinsics.%InitialGetStackString%.arguments
Tolerating undeletable intrinsics.%InitialGetStackString%.arguments
Removing intrinsics.%InitialGetStackString%.prototype
Tolerating undeletable intrinsics.%InitialGetStackString%.prototype === undefined
% Initial InitialError
Removing intrinsics.%InitialError%.caller
Tolerating undeletable intrinsics.%InitialError%.caller
Removing intrinsics.%InitialError%.arguments
Tolerating undeletable intrinsics.%InitialError%.arguments
Removing intrinsics.%InitialError%.stackTraceLimit<get>.caller
Tolerating undeletable intrinsics.%InitialError%.stackTraceLimit<get>.caller
Removing intrinsics.%InitialError%.stackTraceLimit<get>.arguments
Tolerating undeletable intrinsics.%InitialError%.stackTraceLimit<get>.arguments
Removing intrinsics.%InitialError%.stackTraceLimit<get>.prototype
Tolerating undeletable intrinsics.%InitialError%.stackTraceLimit<get>.prototype === undefined
Removing intrinsics.%InitialError%.stackTraceLimit<set>.caller
Tolerating undeletable intrinsics.%InitialError%.stackTraceLimit<set>.caller
Removing intrinsics.%InitialError%.stackTraceLimit<set>.arguments
Tolerating undeletable intrinsics.%InitialError%.stackTraceLimit<set>.arguments
Removing intrinsics.%InitialError%.stackTraceLimit<set>.prototype
Tolerating undeletable intrinsics.%InitialError%.stackTraceLimit<set>.prototype === undefined
Removing intrinsics.%InitialError%.captureStackTrace.caller
Tolerating undeletable intrinsics.%InitialError%.captureStackTrace.caller
Removing intrinsics.%InitialError%.captureStackTrace.arguments
Tolerating undeletable intrinsics.%InitialError%.captureStackTrace.arguments
Removing intrinsics.%InitialError%.captureStackTrace.prototype
Tolerating undeletable intrinsics.%InitialError%.captureStackTrace.prototype === undefined
Removing intrinsics.%InitialError%.prepareStackTrace<get>.caller
Tolerating undeletable intrinsics.%InitialError%.prepareStackTrace<get>.caller
Removing intrinsics.%InitialError%.prepareStackTrace<get>.arguments
Tolerating undeletable intrinsics.%InitialError%.prepareStackTrace<get>.arguments
Removing intrinsics.%InitialError%.prepareStackTrace<get>.prototype
Tolerating undeletable intrinsics.%InitialError%.prepareStackTrace<get>.prototype === undefined
Removing intrinsics.%InitialError%.prepareStackTrace<set>.caller
Tolerating undeletable intrinsics.%InitialError%.prepareStackTrace<set>.caller
Removing intrinsics.%InitialError%.prepareStackTrace<set>.arguments
Tolerating undeletable intrinsics.%InitialError%.prepareStackTrace<set>.arguments
Removing intrinsics.%InitialError%.prepareStackTrace<set>.prototype
Tolerating undeletable intrinsics.%InitialError%.prepareStackTrace<set>.prototype === undefined
% Shared Error
Removing intrinsics.%SharedError%.caller
Tolerating undeletable intrinsics.%SharedError%.caller
Removing intrinsics.%SharedError%.arguments
Tolerating undeletable intrinsics.%SharedError%.arguments
Removing intrinsics.%SharedError%.stackTraceLimit<get>.caller
Tolerating undeletable intrinsics.%SharedError%.stackTraceLimit<get>.caller
Removing intrinsics.%SharedError%.stackTraceLimit<get>.arguments
Tolerating undeletable intrinsics.%SharedError%.stackTraceLimit<get>.arguments
Removing intrinsics.%SharedError%.stackTraceLimit<get>.prototype
Tolerating undeletable intrinsics.%SharedError%.stackTraceLimit<get>.prototype === undefined
Removing intrinsics.%SharedError%.stackTraceLimit<set>.caller
Tolerating undeletable intrinsics.%SharedError%.stackTraceLimit<set>.caller
Removing intrinsics.%SharedError%.stackTraceLimit<set>.arguments
Tolerating undeletable intrinsics.%SharedError%.stackTraceLimit<set>.arguments
Removing intrinsics.%SharedError%.stackTraceLimit<set>.prototype
Tolerating undeletable intrinsics.%SharedError%.stackTraceLimit<set>.prototype === undefined
Removing intrinsics.%SharedError%.prepareStackTrace<get>.caller
Tolerating undeletable intrinsics.%SharedError%.prepareStackTrace<get>.caller
Removing intrinsics.%SharedError%.prepareStackTrace<get>.arguments
Tolerating undeletable intrinsics.%SharedError%.prepareStackTrace<get>.arguments
Removing intrinsics.%SharedError%.prepareStackTrace<get>.prototype
Tolerating undeletable intrinsics.%SharedError%.prepareStackTrace<get>.prototype === undefined
Removing intrinsics.%SharedError%.prepareStackTrace<set>.caller
Tolerating undeletable intrinsics.%SharedError%.prepareStackTrace<set>.caller
Removing intrinsics.%SharedError%.prepareStackTrace<set>.arguments
Tolerating undeletable intrinsics.%SharedError%.prepareStackTrace<set>.arguments
Removing intrinsics.%SharedError%.prepareStackTrace<set>.prototype
Tolerating undeletable intrinsics.%SharedError%.prepareStackTrace<set>.prototype === undefined
Removing intrinsics.%SharedError%.captureStackTrace.caller
Tolerating undeletable intrinsics.%SharedError%.captureStackTrace.caller
Removing intrinsics.%SharedError%.captureStackTrace.arguments
Tolerating undeletable intrinsics.%SharedError%.captureStackTrace.arguments
Removing intrinsics.%SharedError%.captureStackTrace.prototype
Tolerating undeletable intrinsics.%SharedError%.captureStackTrace.prototype === undefined
% Shared Math
Removing intrinsics.%SharedMath%.random.caller
Tolerating undeletable intrinsics.%SharedMath%.random.caller
Removing intrinsics.%SharedMath%.random.arguments
Tolerating undeletable intrinsics.%SharedMath%.random.arguments
Removing intrinsics.%SharedMath%.random.prototype
Tolerating undeletable intrinsics.%SharedMath%.random.prototype === undefined
% Initial RegExp
Removing intrinsics.%InitialRegExp%.caller
Tolerating undeletable intrinsics.%InitialRegExp%.caller
Removing intrinsics.%InitialRegExp%.arguments
Tolerating undeletable intrinsics.%InitialRegExp%.arguments
% Initial Shared RegExp
Removing intrinsics.%SharedRegExp%.caller
Tolerating undeletable intrinsics.%SharedRegExp%.caller
Removing intrinsics.%SharedRegExp%.arguments
Tolerating undeletable intrinsics.%SharedRegExp%.arguments
% Initial SharedSymbol
Removing intrinsics.%SharedSymbol%.caller
Tolerating undeletable intrinsics.%SharedSymbol%.caller
Removing intrinsics.%SharedSymbol%.arguments
Tolerating undeletable intrinsics.%SharedSymbol%.arguments
% Inert Compartment
Removing intrinsics.%InertCompartment%.caller
Tolerating undeletable intrinsics.%InertCompartment%.caller
Removing intrinsics.%InertCompartment%.arguments
Tolerating undeletable intrinsics.%InertCompartment%.arguments
% Number Prototype
Removing intrinsics.%NumberPrototype%.toLocaleString.caller
Tolerating undeletable intrinsics.%NumberPrototype%.toLocaleString.caller
Removing intrinsics.%NumberPrototype%.toLocaleString.arguments
Tolerating undeletable intrinsics.%NumberPrototype%.toLocaleString.arguments
Removing intrinsics.%NumberPrototype%.toLocaleString.prototype
Tolerating undeletable intrinsics.%NumberPrototype%.toLocaleString.prototype === undefined
% Promise Prototype
Removing intrinsics.%PromisePrototype%.then.caller
Tolerating undeletable intrinsics.%PromisePrototype%.then.caller
Removing intrinsics.%PromisePrototype%.then.arguments
Tolerating undeletable intrinsics.%PromisePrototype%.then.arguments
Removing intrinsics.%PromisePrototype%.then.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.then.prototype === undefined
Removing intrinsics.%PromisePrototype%.catch.caller
Tolerating undeletable intrinsics.%PromisePrototype%.catch.caller
Removing intrinsics.%PromisePrototype%.catch.arguments
Tolerating undeletable intrinsics.%PromisePrototype%.catch.arguments
Removing intrinsics.%PromisePrototype%.catch.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.catch.prototype === undefined
Removing intrinsics.%PromisePrototype%.finally.caller
Tolerating undeletable intrinsics.%PromisePrototype%.finally.caller
Removing intrinsics.%PromisePrototype%.finally.arguments
Tolerating undeletable intrinsics.%PromisePrototype%.finally.arguments
Removing intrinsics.%PromisePrototype%.finally.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.finally.prototype === undefined
% String Prototype
Removing intrinsics.%StringPrototype%.localeCompare.caller
Tolerating undeletable intrinsics.%StringPrototype%.localeCompare.caller
Removing intrinsics.%StringPrototype%.localeCompare.arguments
Tolerating undeletable intrinsics.%StringPrototype%.localeCompare.arguments
Removing intrinsics.%StringPrototype%.localeCompare.prototype
Tolerating undeletable intrinsics.%StringPrototype%.localeCompare.prototype === undefined
% Function Prototype
Removing intrinsics.%FunctionPrototype%.toString.caller
Tolerating undeletable intrinsics.%FunctionPrototype%.toString.caller
Removing intrinsics.%FunctionPrototype%.toString.arguments
Tolerating undeletable intrinsics.%FunctionPrototype%.toString.arguments
Removing intrinsics.%FunctionPrototype%.toString.prototype
Tolerating undeletable intrinsics.%FunctionPrototype%.toString.prototype === undefined
% Compartment Prototype
Removing intrinsics.%CompartmentPrototype%.globalThis<get>.caller
Tolerating undeletable intrinsics.%CompartmentPrototype%.globalThis<get>.caller
Removing intrinsics.%CompartmentPrototype%.globalThis<get>.arguments
Tolerating undeletable intrinsics.%CompartmentPrototype%.globalThis<get>.arguments
Removing intrinsics.%CompartmentPrototype%.globalThis<get>.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.globalThis<get>.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.name<get>.caller
Tolerating undeletable intrinsics.%CompartmentPrototype%.name<get>.caller
Removing intrinsics.%CompartmentPrototype%.name<get>.arguments
Tolerating undeletable intrinsics.%CompartmentPrototype%.name<get>.arguments
Removing intrinsics.%CompartmentPrototype%.name<get>.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.name<get>.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.evaluate.caller
Tolerating undeletable intrinsics.%CompartmentPrototype%.evaluate.caller
Removing intrinsics.%CompartmentPrototype%.evaluate.arguments
Tolerating undeletable intrinsics.%CompartmentPrototype%.evaluate.arguments
Removing intrinsics.%CompartmentPrototype%.evaluate.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.evaluate.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.module.caller
Tolerating undeletable intrinsics.%CompartmentPrototype%.module.caller
Removing intrinsics.%CompartmentPrototype%.module.arguments
Tolerating undeletable intrinsics.%CompartmentPrototype%.module.arguments
Removing intrinsics.%CompartmentPrototype%.module.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.module.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.import.caller
Tolerating undeletable intrinsics.%CompartmentPrototype%.import.caller
Removing intrinsics.%CompartmentPrototype%.import.arguments
Tolerating undeletable intrinsics.%CompartmentPrototype%.import.arguments
Removing intrinsics.%CompartmentPrototype%.load.caller
Tolerating undeletable intrinsics.%CompartmentPrototype%.load.caller
Removing intrinsics.%CompartmentPrototype%.load.arguments
Tolerating undeletable intrinsics.%CompartmentPrototype%.load.arguments
Removing intrinsics.%CompartmentPrototype%.importNow.caller
Tolerating undeletable intrinsics.%CompartmentPrototype%.importNow.caller
Removing intrinsics.%CompartmentPrototype%.importNow.arguments
Tolerating undeletable intrinsics.%CompartmentPrototype%.importNow.arguments
Removing intrinsics.%CompartmentPrototype%.importNow.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.importNow.prototype === undefined
in summary
- Promise .caller
- Promise .resolve (including .prototype)
- Promise .all (including .prototype)
- Promise .reject (including .prototype)
- Promise .race (including .prototype)
- lockdown (including .prototype)
- harden (including .prototype)
- % Inert Function
- % Inert Generator Function
- % Inert Async Function
- % Initial Date
- % Shared Date (including .prototype)
- % Initial GetStackString
- % Initial InitialError (including .prototype with stack traces)
- % Shared Error (including .prototype with stack traces)
- % Shared Math (including .prototype)
- % Initial RegExp
- % Initial Shared RegExp
- % Initial SharedSymbol
- % Inert Compartment
- % Number Prototype (including .prototype)
- % Promise Prototype (including .prototype)
- % String Prototype (including .prototype)
- % Function Prototype (including .prototype)
- % Compartment Prototype (including .prototype)
There was a problem hiding this comment.
What is different about how they are defined?
should hopefully figure this soon from Hermes source code
There was a problem hiding this comment.
At least in the case of the Promise subtree, I have an answer: facebook/hermes#1009 (comment)
As described here, Hermes implements Promise by using the Promise polyfill https://github.com/then/promise, which unfortunately isn't fully compliant. This was done to ensure compatibility with React Native, which was already using it before Hermes.
...and that polyfill uses naïve functions: https://github.com/then/promise/blob/9d5851d7adefde580589a041ebfcbd030d39f6fd/src/core.js#L72
Promise.prototype.then = function(onFulfilled, onRejected) { };
There was a problem hiding this comment.
set them to undefined
unfortunately we can't cauterize .caller or .arguments on Hermes (like .prototype) for any intrinsic
i.e. obj[prop], obj[prop] = undefined, obj.caller, Promise.arguments, Promise.all.caller, etc
hit us with Uncaught TypeError: Restricted in strict mode
There was a problem hiding this comment.
how about we handle this in the permit on Hermes (similar to earlier)
then remaining prototypes are successfully cauterized 🔥 too
Hermes VM output (fixed via permits.js)
➜ endo git:(ses-hermes) ✗ yarn build:hermes && yarn test:hermes
-- Building 'hermes' version of SES --
Bundle size: 448750 bytes
Copied ./types.d.ts to ./dist/types.d.cts
Concatenating: dist/ses-hermes.cjs + test/_hermes-smoke.js
Generated: test/_hermes-smoke-dist.js
Executing: test/_hermes-smoke-dist.js on Hermes compiler
test/_hermes-smoke-dist.js:13021:27: warning: the variable "Compartment" was not declared in function "?anon_0_?anon_0_testCompartmentHooks"
const compartment = new Compartment({}, {}, { resolveHook, importHook });
^~~~~~~~~~~
test/_hermes-smoke-dist.js:13029:3: warning: the variable "assert" was not declared in function "?anon_0_?anon_0_testCompartmentHooks"
assert(module);
^~~~~~
test/_hermes-smoke-dist.js:3828:12: warning: the variable "AggregateError" was not declared in anonymous function " 119#"
if( typeof AggregateError!== 'undefined') {
^~~~~~~~~~~~~~
test/_hermes-smoke-dist.js:7065:5: warning: the variable "console" was not declared in function "getOwnPropertyDescriptor"
console.warn(
^~~~~~~
test/_hermes-smoke-dist.js:8625:5: warning: the variable "harden" was not declared in arrow function "makeCausalConsoleFromLogger"
harden(baseConsole);
^~~~~~
test/_hermes-smoke-dist.js:12992:3: warning: the variable "lockdown" was not declared in arrow function "testLockdown"
lockdown();
^~~~~~~~
Generated: test/_hermes-smoke-dist.hbc
Hermes compiler done
Executing generated bytecode file on Hermes VM
Skipping assertDirectEvalAvailable
Removing lockdown.prototype
Tolerating undeletable lockdown.prototype === undefined
Removing harden.prototype
Tolerating undeletable harden.prototype === undefined
Removing %InitialGetStackString%.prototype
Tolerating undeletable %InitialGetStackString%.prototype === undefined
SES Removing unpermitted intrinsics
Removing intrinsics.Promise._l
Removing intrinsics.Promise._m
Removing intrinsics.Promise._n
Removing intrinsics.Promise.resolve.prototype
Tolerating undeletable intrinsics.Promise.resolve.prototype === undefined
Removing intrinsics.Promise.all.prototype
Tolerating undeletable intrinsics.Promise.all.prototype === undefined
Removing intrinsics.Promise.reject.prototype
Tolerating undeletable intrinsics.Promise.reject.prototype === undefined
Removing intrinsics.Promise.race.prototype
Tolerating undeletable intrinsics.Promise.race.prototype === undefined
Removing intrinsics.lockdown.prototype
Tolerating undeletable intrinsics.lockdown.prototype === undefined
Removing intrinsics.harden.prototype
Tolerating undeletable intrinsics.harden.prototype === undefined
Removing intrinsics.%SharedDate%.now.prototype
Tolerating undeletable intrinsics.%SharedDate%.now.prototype === undefined
Removing intrinsics.%InitialGetStackString%.prototype
Tolerating undeletable intrinsics.%InitialGetStackString%.prototype === undefined
Removing intrinsics.%InitialError%.stackTraceLimit<get>.prototype
Tolerating undeletable intrinsics.%InitialError%.stackTraceLimit<get>.prototype === undefined
Removing intrinsics.%InitialError%.stackTraceLimit<set>.prototype
Tolerating undeletable intrinsics.%InitialError%.stackTraceLimit<set>.prototype === undefined
Removing intrinsics.%InitialError%.captureStackTrace.prototype
Tolerating undeletable intrinsics.%InitialError%.captureStackTrace.prototype === undefined
Removing intrinsics.%InitialError%.prepareStackTrace<get>.prototype
Tolerating undeletable intrinsics.%InitialError%.prepareStackTrace<get>.prototype === undefined
Removing intrinsics.%InitialError%.prepareStackTrace<set>.prototype
Tolerating undeletable intrinsics.%InitialError%.prepareStackTrace<set>.prototype === undefined
Removing intrinsics.%SharedError%.stackTraceLimit<get>.prototype
Tolerating undeletable intrinsics.%SharedError%.stackTraceLimit<get>.prototype === undefined
Removing intrinsics.%SharedError%.stackTraceLimit<set>.prototype
Tolerating undeletable intrinsics.%SharedError%.stackTraceLimit<set>.prototype === undefined
Removing intrinsics.%SharedError%.prepareStackTrace<get>.prototype
Tolerating undeletable intrinsics.%SharedError%.prepareStackTrace<get>.prototype === undefined
Removing intrinsics.%SharedError%.prepareStackTrace<set>.prototype
Tolerating undeletable intrinsics.%SharedError%.prepareStackTrace<set>.prototype === undefined
Removing intrinsics.%SharedError%.captureStackTrace.prototype
Tolerating undeletable intrinsics.%SharedError%.captureStackTrace.prototype === undefined
Removing intrinsics.%SharedMath%.random.prototype
Tolerating undeletable intrinsics.%SharedMath%.random.prototype === undefined
Removing intrinsics.%NumberPrototype%.toLocaleString.prototype
Tolerating undeletable intrinsics.%NumberPrototype%.toLocaleString.prototype === undefined
Removing intrinsics.%PromisePrototype%.then.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.then.prototype === undefined
Removing intrinsics.%PromisePrototype%.catch.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.catch.prototype === undefined
Removing intrinsics.%PromisePrototype%.finally.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.finally.prototype === undefined
Removing intrinsics.%StringPrototype%.localeCompare.prototype
Tolerating undeletable intrinsics.%StringPrototype%.localeCompare.prototype === undefined
Removing intrinsics.%FunctionPrototype%.toString.prototype
Tolerating undeletable intrinsics.%FunctionPrototype%.toString.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.globalThis<get>.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.globalThis<get>.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.name<get>.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.name<get>.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.evaluate.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.evaluate.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.module.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.module.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.importNow.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.importNow.prototype === undefined
Hermes VM done
Hermes tests complete
Removing: test/_hermes-smoke-dist.js
Removing: test/_hermes-smoke-dist.hbcThere was a problem hiding this comment.
CI indicating flakey Browser tests failing atm again
Run npx playwright install --with-deps
npx playwright install --with-deps
shell: /usr/bin/bash -e {0}
Installing dependencies...
Switching to root user to install dependencies...
Get:1 file:/etc/apt/apt-mirrors.txt Mirrorlist [14[2](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:2) B]
Hit:2 http://azure.archive.ubuntu.com/ubuntu noble InRelease
Get:[3](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:3) http://azure.archive.ubuntu.com/ubuntu noble-updates InRelease [126 kB]
Hit:6 https://packages.microsoft.com/repos/azure-cli noble InRelease
Get:[4](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:5) http://azure.archive.ubuntu.com/ubuntu noble-backports InRelease [126 kB]
Get:[5](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:6) http://azure.archive.ubuntu.com/ubuntu noble-security InRelease [12[6](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:7) kB]
Hit:7 https://packages.microsoft.com/ubuntu/24.04/prod noble InRelease
Get:8 http://azure.archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages [[7](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:8)01 kB]
Get:9 http://azure.archive.ubuntu.com/ubuntu noble-updates/main Translation-en [162 kB]
Get:10 http://azure.archive.ubuntu.com/ubuntu noble-updates/main amd64 Components [132 kB]
Get:11 http://azure.archive.ubuntu.com/ubuntu noble-updates/universe amd64 Packages [727 kB]
Get:12 http://azure.archive.ubuntu.com/ubuntu noble-updates/universe Translation-en [216 kB]
Get:13 http://azure.archive.ubuntu.com/ubuntu noble-updates/universe amd64 Components [310 kB]
Get:14 http://azure.archive.ubuntu.com/ubuntu noble-updates/restricted amd64 Components [212 B]
Get:15 http://azure.archive.ubuntu.com/ubuntu noble-updates/multiverse amd64 Components [940 B]
Get:16 http://azure.archive.ubuntu.com/ubuntu noble-backports/main amd64 Components [20[8](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:9) B]
Get:17 http://azure.archive.ubuntu.com/ubuntu noble-backports/universe amd64 Components [11.7 kB]
Get:18 http://azure.archive.ubuntu.com/ubuntu noble-backports/restricted amd64 Components [216 B]
Get:1[9](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:10) http://azure.archive.ubuntu.com/ubuntu noble-backports/multiverse amd64 Components [212 B]
Get:20 http://azure.archive.ubuntu.com/ubuntu noble-security/main amd64 Packages [501 kB]
Get:21 http://azure.archive.ubuntu.com/ubuntu noble-security/main Translation-en [[10](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:11)2 kB]
Get:22 http://azure.archive.ubuntu.com/ubuntu noble-security/main amd64 Components [7188 B]
Get:23 http://azure.archive.ubuntu.com/ubuntu noble-security/universe amd64 Components [51.9 kB]
Get:24 http://azure.archive.ubuntu.com/ubuntu noble-security/restricted amd64 Components [212 B]
Get:25 http://azure.archive.ubuntu.com/ubuntu noble-security/multiverse amd64 Components [212 B]
Fetched 3303 kB in 1s (6182 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
Package libasound2 is a virtual package provided by:
liboss4-salsa-asound2 4.2-build2020-1ubuntu3
libasound2t64 1.2.[11](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:12)-1build2 (= 1.2.11-1build2)
Package libicu70 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
E: Package 'libasound2' has no installation candidate
E: Package 'libicu70' has no installation candidate
E: Unable to locate package libffi7
E: Unable to locate package libx264-[16](https://github.com/endojs/endo/actions/runs/12281686710/job/34271115469?pr=2655#step:9:17)3
Failed to install browsers
Error: Installation process exited with code: 100
Error: Process completed with exit code 1.edit: opened
erights
left a comment
There was a problem hiding this comment.
I really do not understand what Hermes is trying to do here with strictness, .caller, and .arguments. Do we know any of the Hermes people? Would be good to invite to an upcoming Endo meeting to discuss. But not today's as I will not be able to attend.
It is hard for me to form a judgement of what to do about this anomalous behavior without understanding what Hermes is trying to do, and why. At the moment, it makes no sense to me.
Once we understand this, I suspect the right fix is to send a PR upstream to Hermes, and then to do an expedient and reversible local "fix" until we can depend on that Hermes upgrade. That expedient temporary fix may very well be what you've already done. But I don't know enough yet to judge.
|
For your amusement: implementation divergence w.r.t. function
Details$ eshost -h 'Hermes,JavaScriptCore,SpiderMonkey,V8,*XS' -sx '
(function(){
const gOPD = Object.getOwnPropertyDescriptors;
const throwTypeErrors = new Set(
[Function.prototype, function(){ "use strict"; }]
.map(fn => gOPD(fn))
.flatMap(d => [d?.caller, d?.arguments].flatMap(d => [d?.get, d?.set]))
.filter(getOrSet => !!getOrSet),
);
if (throwTypeErrors.size === 0) throw Error("no %ThrowTypeError%");
if (throwTypeErrors.size > 1) print(`(${throwTypeErrors.size}+ distinct %ThrowTypeError%s)`);
const repr = val => {
if (val === null || val === undefined) return String(val);
if (throwTypeErrors.has(val)) return "%ThrowTypeError%";
if (typeof val === "function") return `function ${val.name || String(val)}`;
return `${typeof val} ${String(val)}`;
};
const cases = {
"%Function.prototype%": Function.prototype,
"Function()": Function(),
"function(){}": function(){},
"function(){ \"use strict\"; }": function(){ "use strict"; },
};
for(const [label, obj] of Object.entries(cases)) {
print("\n# " + label);
const descriptors = gOPD(obj);
for(const k of Object.keys(descriptors).sort()) {
if (!["arguments", "caller"].includes(k)) continue;
const desc = descriptors[k];
const { value, get, set } = desc;
print(
k,
`[${["writable", "enumerable", "configurable"].filter(attr => desc[attr])}]:`,
get || set ? `<get ${repr(get)}, set ${repr(set)}>` : repr(value),
);
}
}
})();'
#### Hermes
# %Function.prototype%
# Function()
# function(){}
# function(){ "use strict"; }
arguments []: <get %ThrowTypeError%, set %ThrowTypeError%>
caller []: <get %ThrowTypeError%, set %ThrowTypeError%>
#### JavaScriptCore, SpiderMonkey
(4+ distinct %ThrowTypeError%s)
# %Function.prototype%
arguments [configurable]: <get %ThrowTypeError%, set %ThrowTypeError%>
caller [configurable]: <get %ThrowTypeError%, set %ThrowTypeError%>
# Function()
# function(){}
# function(){ "use strict"; }
#### Moddable XS
# %Function.prototype%
arguments [configurable]: <get %ThrowTypeError%, set %ThrowTypeError%>
caller [configurable]: <get %ThrowTypeError%, set %ThrowTypeError%>
# Function()
caller [writable,configurable]: undefined
# function(){}
caller [writable,configurable]: undefined
# function(){ "use strict"; }
#### V8
# %Function.prototype%
arguments [configurable]: <get %ThrowTypeError%, set %ThrowTypeError%>
caller [configurable]: <get %ThrowTypeError%, set %ThrowTypeError%>
# Function()
arguments []: null
caller []: null
# function(){}
arguments []: null
caller []: null
# function(){ "use strict"; }
Detailsin a module context, $ for m in '' '-m'; do eshost $m -h Hermes -se 'Object.entries({
"Function()": Function(),
"function(){}": function(){},
"function(){ \"use strict\"; }": function(){ "use strict"; },
})
.map(
([s, f]) => `${s} [${["caller", "arguments"].filter(p => Object.hasOwn(f, p))}]`,
)
.join("\n")'; done
#### Hermes
Function() []
function(){} []
function(){ "use strict"; } [caller,arguments]
#### Hermes
Function() []
function(){} []
function(){ "use strict"; } [caller,arguments] |
|
@gibson042 , thanks for the thorough analysis! Do you happen to know if these non-conformances show up in test262 tests? |
What's the consequence of this? At best reaching for these properties doesn't throw for the non-explicitly strict functions? Still can't access |
Not that I know of. I opened tc39/test262#4340 to track it, and anba replied with references to tc39/ecma262#562 and https://github.com/claudepache/es-legacy-function-reflection . Do you know to what extent those are still relevant?
Right, we get $ eshost -h Hermes,V8,SpiderMonkey -mse 'Object.entries({
"Function()": Function(),
"function(){}": function(){},
"function(){ \"use strict\"; }": function(){ "use strict"; },
}).map(Object.defineProperty(Function("entry", `
const [s, f] = entry;
f();
try {
const { caller } = f;
return \`$\{s}.caller is $\{caller?.name || String(caller)}\`;
} catch (err) {
return \`$\{s}.caller throws $\{err.name} $\{err.message}\`;
}
`), "name", { value: "checkCaller" }))
.join("\n")'
#### Hermes
Function().caller is undefined
function(){}.caller is undefined
function(){ "use strict"; }.caller throws TypeError Restricted in strict mode
#### SpiderMonkey, V8
Function().caller is null
function(){}.caller throws TypeError 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
function(){ "use strict"; }.caller throws TypeError 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them |
raised the issue here with some more details that may help, @tmikov wdyt? edit: Fixed and now configurable in Static Hermes |
|
before facebook/hermes#1582 (comment) ➜ endo git:(ses-hermes) ✗ yarn build:hermes && yarn test:hermes
-- Building 'hermes' version of SES --
Bundle size: 448793 bytes
Copied ./types.d.ts to ./dist/types.d.cts
Concatenating: dist/ses-hermes.cjs + test/_hermes-smoke.js
Generated: test/_hermes-smoke-dist.js
Executing: test/_hermes-smoke-dist.js on Hermes compiler...(warnings)
Generated: test/_hermes-smoke-dist.hbc
Hermes compiler done
Executing generated bytecode file on Hermes VM
Skipping assertDirectEvalAvailable
SES Removing unpermitted intrinsics
Removing intrinsics.Promise._l
Removing intrinsics.Promise._m
Removing intrinsics.Promise._n
Removing intrinsics.Promise.resolve.prototype
Tolerating undeletable intrinsics.Promise.resolve.prototype === undefined
Removing intrinsics.Promise.all.prototype
Tolerating undeletable intrinsics.Promise.all.prototype === undefined
Removing intrinsics.Promise.allSettled.prototype
Tolerating undeletable intrinsics.Promise.allSettled.prototype === undefined
Removing intrinsics.Promise.reject.prototype
Tolerating undeletable intrinsics.Promise.reject.prototype === undefined
Removing intrinsics.Promise.race.prototype
Tolerating undeletable intrinsics.Promise.race.prototype === undefined
Removing intrinsics.Promise.any.prototype
Tolerating undeletable intrinsics.Promise.any.prototype === undefined
Removing intrinsics.%PromisePrototype%.then.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.then.prototype === undefined
Removing intrinsics.%PromisePrototype%.catch.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.catch.prototype === undefined
Removing intrinsics.%PromisePrototype%.finally.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.finally.prototype === undefined
failed to delete intrinsics.%FunctionPrototype%.caller TypeError: Property is not configurable
Uncaught TypeError: Property is not configurableafter ➜ endo git:(ses-hermes) ✗ yarn build:hermes && yarn test:hermes
-- Building 'hermes' version of SES --
Bundle size: 448793 bytes
Copied ./types.d.ts to ./dist/types.d.cts
Concatenating: dist/ses-hermes.cjs + test/_hermes-smoke.js
Generated: test/_hermes-smoke-dist.js
Executing: test/_hermes-smoke-dist.js on Hermes compiler...(warnings)
Generated: test/_hermes-smoke-dist.hbc
Hermes compiler done
Executing generated bytecode file on Hermes VM
Skipping assertDirectEvalAvailable
SES Removing unpermitted intrinsics
Removing intrinsics.Promise._l
Removing intrinsics.Promise._m
Removing intrinsics.Promise._n
Removing intrinsics.Promise.resolve.prototype
Tolerating undeletable intrinsics.Promise.resolve.prototype === undefined
Removing intrinsics.Promise.all.prototype
Tolerating undeletable intrinsics.Promise.all.prototype === undefined
Removing intrinsics.Promise.allSettled.prototype
Tolerating undeletable intrinsics.Promise.allSettled.prototype === undefined
Removing intrinsics.Promise.reject.prototype
Tolerating undeletable intrinsics.Promise.reject.prototype === undefined
Removing intrinsics.Promise.race.prototype
Tolerating undeletable intrinsics.Promise.race.prototype === undefined
Removing intrinsics.Promise.any.prototype
Tolerating undeletable intrinsics.Promise.any.prototype === undefined
Removing intrinsics.%PromisePrototype%.then.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.then.prototype === undefined
Removing intrinsics.%PromisePrototype%.catch.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.catch.prototype === undefined
Removing intrinsics.%PromisePrototype%.finally.prototype
Tolerating undeletable intrinsics.%PromisePrototype%.finally.prototype === undefined
(intrinsics.%FunctionPrototype%.caller deleted)
(intrinsics.%FunctionPrototype%.arguments deleted)
Removing intrinsics.%CompartmentPrototype%.globalThis<get>.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.globalThis<get>.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.name<get>.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.name<get>.prototype === undefined
Hermes VM doneare we happy with the temp permits.js fix? until Static Hermes is released and Hermes is deprecated edit: Removing intrinsics.%CompartmentPrototype%.globalThis<get>.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.globalThis<get>.prototype === undefined
Removing intrinsics.%CompartmentPrototype%.name<get>.prototype
Tolerating undeletable intrinsics.%CompartmentPrototype%.name<get>.prototype === undefinedlooks like a separate issue edit: note on SES undeletable Promise intrinsics on Hermes VM facebook/hermes#1009 (comment)
|
erights
left a comment
There was a problem hiding this comment.
With the change, LGTM, thanks!
| 'use strict'; | ||
| }; | ||
|
|
||
| arrayForEach(getOwnPropertyNames(strict), prop => { |
There was a problem hiding this comment.
I prefer that it only be weird for 'caller' and 'arguments' specifically.
| arrayForEach(getOwnPropertyNames(strict), prop => { | |
| // TODO Remove this once we no longer support the Hermes that needed this. | |
| arrayForEach(['caller', 'arguments'], prop => { |
Is there any simple reliable check that we are on Hermes? If so, then perhaps condition on that check as well?
There was a problem hiding this comment.
for temp local debugging in #2334 i've used AsyncGeneratorFunctionInstance
// packages/ses/src/commons.js
// ...
export const AsyncGeneratorFunctionInstance =
getAsyncGeneratorFunctionInstance();
/**
* Print on Hermes VM
* @param {...any} args Arguments to print
*/
export const printHermes = (...args) => {
if (AsyncGeneratorFunctionInstance === undefined) {
// @ts-expect-error ts(2554)
// eslint-disable-next-line no-undef
print(args);
}
};but you're right time for a better reliable check (if exists),
i'll follow-up and add the condition once i find it
edit: fixed the CI lint (removed getOwnPropertyNames import)
8915363 to
d057faf
Compare
Co-authored-by: Mark S. Miller <erights@users.noreply.github.com>
d057faf to
fb31aca
Compare
Follow-up to
Progresses
Description
Fix
removeUnpermittedIntrinsics(previouslywhitelistIntrinsics) on Hermesafter starting again on the problem (now with #2624 addressing
completePrototypes), it boils down to tolerating two more undeletable non-standard properties (.callerand.arguments) on the remaining Hermes functions after attempting to remove themedit: and
.prototypeon some propertiesso we can simply extend
cauterizePropertyafter dealing with prototypes to deal with these additional propertiesrepro
gh pr checkout 2334feat(ses): Shim compatible with Hermes compiler #2334packages/ses/scripts/hermes-test.sh// assertDirectEvalAvailable()inpackages/ses/src/lockdown.jsyarn build:hermesyarn test:hermesHermes VM output (before)
Hermes VM output (after)
Security Considerations
Scaling Considerations
Documentation Considerations
Testing Considerations
Compatibility Considerations
Upgrade Considerations