Skip to content
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

Broken exception stack trace in async arrow function #157

Closed
Nihiue opened this issue Sep 30, 2021 · 2 comments
Closed

Broken exception stack trace in async arrow function #157

Nihiue opened this issue Sep 30, 2021 · 2 comments

Comments

@Nihiue
Copy link

Nihiue commented Sep 30, 2021

Env

Node: v14.17.2
OS: Linux
Bytenode: 1.3.3

Demo

hello-export.js

module.exports.makeSomeError = async () => {
  ''.a();
};

main.js

const bytenode = require('bytenode');
const hello = require('./hello-export.jsc');

hello.makeSomeError()

Run

$ npx bytenode -c hello-export.js
$ node main.js

Output

#
# Fatal error in , line 0
# Check failed: stack_overflow().
#
#
#
#FailureMessage Object: 0x7ffdba37f7c0
 1: 0xa92851  [node]
 2: 0x1a1ac64 V8_Fatal(char const*, ...) [node]
 3: 0xfc1ed1 v8::internal::Parser::DoParseFunction(v8::internal::Isolate*, v8::internal::ParseInfo*, int, int, int, v8::internal::AstRawString const*) [node]
 4: 0xfc230b v8::internal::Parser::ParseFunction(v8::internal::Isolate*, v8::internal::ParseInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>) [node]
 5: 0xfc7081 v8::internal::parsing::ParseFunction(v8::internal::ParseInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Isolate*, v8::internal::parsing::ReportErrorsAndStatisticsMode) [node]
 6: 0xfc74a5 v8::internal::parsing::ParseAny(v8::internal::ParseInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Isolate*, v8::internal::parsing::ReportErrorsAndStatisticsMode) [node]
 7: 0xd05485  [node]
 8: 0xd0a19e v8::internal::ErrorUtils::NewCalledNonCallableError(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>) [node]
 9: 0x1080997 v8::internal::Runtime_ThrowCalledNonCallable(int, unsigned long*, v8::internal::Isolate*) [node]
10: 0x1427079  [node]
Illegal instruction (core dumped)

Note: if replace async arrow function withasync function() {}, the code works fine.

(node:46699) UnhandledPromiseRejectionWarning: TypeError: undefined is not a function
    at Object.makeSomeError (evalmachine.<anonymous>:1:118)
    at Object.<anonymous> (/home/nihi/Repo/LIB/little-byte/play/main.js:4:7)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
    at internal/main/run_main_module.js:17:47
(Use `node --trace-warnings ...` to show where the warning was created)
(node:46699) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:46699) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I read about https://github.com/bytenode/bytenode/issues/106, but i think it is not about puppeteer or Electron, v8 has some bugs here

In node 14.18 source code deps/v8/src/parsing/parser.cc line 918, i found this

 if (IsArrowFunction(kind)) {
      if (IsAsyncFunction(kind)) {
        DCHECK(!scanner()->HasLineTerminatorAfterNext());
        if (!Check(Token::ASYNC)) {
          CHECK(stack_overflow());
          return nullptr;
        }
        if (!(peek_any_identifier() || peek() == Token::LPAREN)) {
          CHECK(stack_overflow());
          return nullptr;
        }
      }

V8 relies on source code to determine whether a function is async arrow function.

So it's dead end here.

I think the best solution is to generate some kind of sourcemap for jsc, which includes function outline (i.e function statement)

if i got some time , i will work on it.

P.S.

I have written some homebrew bytecode libs and articles, which are inspired by bytenode, Big Thanks to You.

https://github.com/Nihiue/little-byte

It's in Chinese, but i think google translation will work :D.

https://translate.google.com/translate?js=n&sl=chinese&tl=en&u=https://github.com/Nihiue/little-byte

@Nihiue Nihiue changed the title Broken exception stack in async () => {} Broken exception stack trace in async () => {} Sep 30, 2021
@Nihiue Nihiue changed the title Broken exception stack trace in async () => {} Broken exception stack trace in async arrow function Sep 30, 2021
@OsamaAbbas
Copy link
Collaborator

So it seems that async arrow functions cause problems if they were called from another file other than where they defined, not only if they are called from another context or another v8 instance.

My position on this issue is that we should not fix it here in bytenode. Especially if the fix needs gigantic libraries and dependencies. Also, the developer can easily add a simple transformation to his project. Most developers nowadays use huge setups that have more than enough to transpile arrow async functions into usual functions.

At best, we can check if the source code contains async arrow functions and warn the user if this is true.

Finally, as I mentioned before, pkg uses v8 bytecode and removes the source code too. We should test your code to see if it works or breaks with pkg.

@Nihiue
Copy link
Author

Nihiue commented Oct 8, 2021

According to my test, pkg dose keep source code by default.

hello-export.js

module.exports.makeSomeError = async () => {
  ''.a();
};

module.exports.printSource = function() {
  console.log('source code: ', module.exports.makeSomeError.toString());
}

main.js

const hello = require('./hello-export.js');

hello.printSource()
hello.makeSomeError()

pkg(v5.3.3) config

 "pkg": {
    "targets": [
      "node14-linux-x64"
    ],
    "outputPath": "dist"
  }

Run binary

source code:  async () => {
  ''.a();
}
(node:31814) UnhandledPromiseRejectionWarning: TypeError: "".a is not a function
    at Object.makeSomeError (/snapshot/play/hello-export.js:2:6)
    at Object.<anonymous> (/snapshot/play/main.js:5:7)
    at Module._compile (pkg/prelude/bootstrap.js:1794:22)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
    at Module.load (internal/modules/cjs/loader.js:937:32)
    at Function.Module._load (internal/modules/cjs/loader.js:778:12)
    at Function.runMain (pkg/prelude/bootstrap.js:1847:12)
    at internal/main/run_main_module.js:17:47

Also, my demo for soucemap seems to work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants