LavaMoat / docs

React Native docs
1 stars 3 forks source link

RN 0.66.5 + SES 0.18.1: Error failed to del intrinsics.%AsyncGenerator%.length #16

Closed leotm closed 1 year ago

leotm commented 1 year ago

Follow-up to

As seen in

No error on iOS jsc

No error on Android v8


lockdown({consoleTaming: 'unsafe'});
 WARN  Removing intrinsics.Promise._B
 WARN  Removing intrinsics.Promise._C
 WARN  Removing intrinsics.Promise._D
 WARN  Removing intrinsics.Promise.resolve.prototype
 WARN  Tolerating undeletable intrinsics.Promise.resolve.prototype === undefined
 WARN  Removing intrinsics.Promise.all.prototype
 WARN  Tolerating undeletable intrinsics.Promise.all.prototype === undefined
 WARN  Removing intrinsics.Promise.allSettled.prototype
 WARN  Tolerating undeletable intrinsics.Promise.allSettled.prototype === undefined
 WARN  Removing intrinsics.Promise.reject.prototype
 WARN  Tolerating undeletable intrinsics.Promise.reject.prototype === undefined
 WARN  Removing intrinsics.Promise.race.prototype
 WARN  Tolerating undeletable intrinsics.Promise.race.prototype === undefined
 WARN  Removing intrinsics.%AsyncGenerator%.length
 ERROR  failed to delete intrinsics.%AsyncGenerator%.length [TypeError: Unable to delete property.]
 ERROR  TypeError: Unable to delete property.
 ERROR  Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect.
      This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.

Android emu: screenshot, then tapping empty white view

 ERROR  Invariant Violation: Module RCTEventEmitter is not a registered callable module (calling receiveTouches). A frequent cause of the error is that the application entry file path is incorrect.
      This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.

Bundle: http://localhost:8081/index.bundle?platform=android

es2018.asyncgenerator https://tc39.es/proposal-async-iteration/#sec-well-known-intrinsic-objects-patch https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator https://github.com/tc39/proposal-async-iteration#async-generator-functions

Our AsyncGenerator is defined in our whitelist.js

  '%InertAsyncGeneratorFunction%': {
    // Properties of the AsyncGeneratorFunction Constructor
    '[[Proto]]': '%InertFunction%',
    prototype: '%AsyncGenerator%',
  },

  '%AsyncGenerator%': {
    // Properties of the AsyncGeneratorFunction Prototype Object
    '[[Proto]]': '%FunctionPrototype%',
    constructor: '%InertAsyncGeneratorFunction%',
    prototype: '%AsyncGeneratorPrototype%',
    '@@toStringTag': 'string',
  },

More: https://github.com/search?q=repo%3Aendojs%2Fendo%20%25AsyncGenerator%25&type=code

With methods: AsyncGenerator.prototype.(next|return|throw)

Inheriting prop functions: Function.prototype.(length|name|prototype) (error failing to delete these one or more of these props)

Disabling @babel/plugin-proposal-async-generator-functions is a red herring, despite being required and pushed in our default preset:

// node_modules/metro-react-native-babel-preset/src/configs/main.js
// ...
  if (isNull || src.indexOf("async") !== -1) {
    extraPlugins.push([
      require("@babel/plugin-proposal-async-generator-functions"),
    ]);
    extraPlugins.push([require("@babel/plugin-transform-async-to-generator")]);
  }
// ...

And applying the return _ref.apply(this, arguments); (Out) transform Since disabling it persists the error (and further disabling Babel plugins w/o breaking React Native)

metro-react-native-babel-preset@0.66.2 ❌ (default) metro-react-native-babel-preset@0.75.1 ❌ (bumped) nb: can't bump to 0.76 since this requires Node v16 instead of Node v14 and we're on RN 0.66.5

"@babel/core": "^7.12.9" ❌ (default) "@babel/core": "7.21.0" ❌ (bumped)

"@babel/runtime": "^7.12.5" ❌ (default) "@babel/runtime": "7.21.0" ❌ (bumped)

metro-react-native-babel-preset applies no Android/iOS/jsc/v8-specific transforms (only on Hermes)

It doesn't appear to be Babel transforming android-jsc differently to iOS jsc and/or android-v8

Patch react-native to use "jsc-android": "294992.0.0" (WebKitGTK 2.36.3) instead of default "jsc-android": "^250231.0.0" (WebKitGTK 2.26.1) ❌

Screenshot 2023-03-13 at 13 07 54

Test w/o lockdown

async function* foo() {
  yield await Promise.resolve('a');
  yield await Promise.resolve('b');
  yield await Promise.resolve('c');
}

let str = '';

async function generate() {
  for await (const val of foo()) {
    str = str + val;
  }
  console.log('output', str);
}

generate();

console.log('this', this);
console.log(foo);
console.log('typeof foo:', typeof foo);
console.log('typeof foo.prototype:', typeof foo.prototype);
console.log('length:', foo.length);
console.log('name:', foo.name);
console.log('prototype:', foo.prototype);
console.log(
  'getOwnPropertyDescriptors:',
  Object.getOwnPropertyDescriptors(foo),
);

brave/chrome-v8

Screenshot 2023-03-13 at 16 44 44

RN v8-android

Screenshot 2023-03-13 at 16 05 56

RN android-jsc (not-so-expandable logs output to Metro terminal window)

 LOG  this [Object]
 LOG  [Function foo]
 LOG  typeof foo: function
 LOG  typeof foo.prototype: object
 LOG  foo.length: 0
 LOG  foo.name: foo
 LOG  foo.prototype: {}
 LOG  foo.prototype.constructor: [Function foo]
 LOG  getOwnPropertyDescriptors: {"arguments": {"configurable": false, "enumerable": false, "value": null, "writable": false}, "caller": {"configurable": false, "enumerable": false, "value": null, "writable": false}, "length": {"configurable": true, "enumerable": false, "value": 0, "writable": false}, "name": {"configurable": true, "enumerable": false, "value": "foo", "writable": false}, "prototype": {"configurable": false, "enumerable": false, "value": {}, "writable": true}}
 LOG  output abc

our %AsyncGenerator% exists since it works i.e. we have desired output and it's correct our length descriptor (inherited prop fn from Function.prototype) exists and is configurable, so SES should be able to delete it during lockdown

lockdown.umd.js test (instead of importing ses)

Screenshot 2023-03-13 at 15 31 07

Result

 WARN  Removing intrinsics.%AsyncFunctionPrototype%.length
 ERROR  failed to delete intrinsics.%AsyncFunctionPrototype%.length [TypeError: Unable to delete property.]

But ofc this isn't the right path, but we've got another problem 👆 AsyncFunctionPrototype

Delete snippet of lockdown below

// ...
try {
  delete obj[prop];
} catch (err) {
  if (prop in obj) {
    if (typeof obj === 'function' && prop === 'prototype') {
      obj.prototype = undefined;
      if (obj.prototype === undefined) {
        // eslint-disable-next-line @endo/no-polymorphic-call
        console.warn(
          `Tolerating undeletable ${subPath} === undefined`,
        );
        // eslint-disable-next-line no-continue
        continue;
      }
    }
    // eslint-disable-next-line @endo/no-polymorphic-call
    console.error(`failed to delete ${subPath}`, err);
  } else {
    // eslint-disable-next-line @endo/no-polymorphic-call
    console.error(`deleting ${subPath} threw`, err);
  }
  throw err;
}
// ...

Adding logs

 WARN  Removing intrinsics.%AsyncGenerator%.length
 LOG  {"obj": {}}
 LOG  {"prop": "length"}
 LOG  obj[prop] 0
 ERROR  failed to delete intrinsics.%AsyncGenerator%.length [TypeError: Unable to delete property.]
 ERROR  TypeError: Unable to delete property.

Why when we call lockdown with android-jsc (WebKitGTK) our %AsyncGenerator% obj doesn't exist (to delete it's props), but it works w/o calling lockdown 🤔

# JSC
 LOG  {"obj": [Function Function]}
 LOG  {"obj": [Function GeneratorFunction]}
 LOG  {"obj": [Function AsyncFunction]}
 LOG  {"obj": [Function AsyncGeneratorFunction]}
 LOG  {"obj": [Function Date]}
 LOG  {"obj": [Function parse]}
 LOG  {"obj": [Function UTC]}
 LOG  {"obj": [Function now]}
 LOG  {"obj": [Function Date]}
 LOG  {"obj": [Function parse]}
 LOG  {"obj": [Function UTC]}
 LOG  {"obj": [Function now]}
 LOG  {"obj": [Function getStackString]}
 LOG  {"obj": [Function Error]}
 LOG  {"obj": [Function get]}
 LOG  {"obj": [Function set]}
 LOG  {"obj": [Function Error]}
 LOG  {"obj": [Function get]}
 LOG  {"obj": [Function set]}
 LOG  {"obj": {}}
 LOG  {"obj": [Function abs]}
 LOG  {"obj": [Function acos]}
# ...
 LOG  {"obj": [Function tanh]}
 LOG  {"obj": [Function trunc]}
 LOG  {"obj": [Function imul]}
 LOG  {"obj": {}}
 LOG  {"obj": [Function abs]}
 LOG  {"obj": [Function acos]}
# ...
 LOG  {"obj": [Function RegExp]}
 LOG  {"obj": [Function get [Symbol.species]]}
 LOG  {"obj": [Function RegExp]}
 LOG  {"obj": [Function get [Symbol.species]]}
 LOG  {"obj": {}}
 LOG  {"obj": [Function next]}
 LOG  {"obj": {}}

V8

Screenshot 2023-03-13 at 21 31 05

After further debugging, issue raised here


lockdown({
  errorTaming: 'unsafe',
  stackFiltering: 'verbose',
  overrideTaming: 'severe',
});

No console output in Metro bundler

Android emu: screenshot (OCR'ed to text below)

undefined is not an object (evaluating '(_console = console)._errorOriginal.apply')

undefined is not an object (evaluating (_console = console)._errorOriginal.apply')

reactConsoleErrorHandler@http://localhost:
8081/index.bundle?platform=android&dev=true &minify=false&app=com.rn665&modulesOnly= false&runModule=true:24784:40
http://localhost:8081/index.bundle?platform=
android&dev=true&minify-false&app=com.rn665 &modulesOnly=false&runModule=true:34732:35 native codel
registerError@http://localhost:8081/index.bundle platform=android&dev=true&minify-false&app= com.rn665&modulesOnly=false&runModule=true:
25268:35
http://localhost:8081/index.bundle?platform=
android&dev=true&minify=false&app=com.rn665 &modulesOnly=false&runModule=true:25162:35 levelMethod@http://localhost:8081/index.bundle
?platform=android&dev=true&minify-false&app= com.rn665&modulesOnly=false&runModule=true:
4724:31
reportException@http://localhost:8081/index bundle?platform=android&dev=true&minify= false&app=com.rn665&modulesOnly=false& runModule=true:24733:22 handleException@http://localhost:8081/index bundle?platform=android&dev=true&minify= false&app=com.rn665&modulesOnly=false& runModule=true:24774:22

Current/only vanilla RN 0.66.5 blocker before metamask-mobile integration

leotm commented 1 year ago

Issue raised in

leotm commented 1 year ago

Next steps to unblock, harmless PR to SES adding length prop, referencing above issue in code comment

leotm commented 1 year ago
leotm commented 1 year ago

Merged ^ 🚀