-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(ses): removeUnpermittedIntrinsics
on Hermes
#2655
fix(ses): removeUnpermittedIntrinsics
on Hermes
#2655
Conversation
d12c2aa
to
d400b04
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is different about how they are defined?
should hopefully figure this soon from Hermes source code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.hbc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
$ 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"; }
in 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 configurable after ➜ 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 done are 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 === undefined looks like a separate issue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the change, LGTM, thanks!
packages/ses/src/permits.js
Outdated
'use strict'; | ||
}; | ||
|
||
arrayForEach(getOwnPropertyNames(strict), prop => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 <[email protected]>
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 (.caller
and.arguments
) on the remaining Hermes functions after attempting to remove themedit: and
.prototype
on some propertiesso we can simply extend
cauterizeProperty
after dealing with prototypes to deal with these additional propertiesrepro
gh pr checkout 2334
feat(ses): Shim compatible with Hermes compiler #2334packages/ses/scripts/hermes-test.sh
// assertDirectEvalAvailable()
inpackages/ses/src/lockdown.js
yarn build:hermes
yarn test:hermes
Hermes VM output (before)
Hermes VM output (after)
Security Considerations
Scaling Considerations
Documentation Considerations
Testing Considerations
Compatibility Considerations
Upgrade Considerations