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

Compiled function token has no original name mapping in produced source map #52483

Open
kamilogorek opened this issue May 23, 2023 · 4 comments
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-dart2js

Comments

@kamilogorek
Copy link

It appears that produced source map mappings are generated in a quite odd name. The produced function token doesn't have a valid reference to its original name, however, brackets that are part of that scope do, eg:

Foo.prototype={
abc(){...}
// ^     ^
// |     | closing brace of fn body
// | opening paren of argument list
}

Or a more concrete example:

A.Tt.prototype={
$0(){throw A.c(A.c2("Test exception"))},
$S:0}

The A.Tt.prototype.$0 scope can’t be resolved, but columns 3 (open paren), 6 (throw), 16 (the second A), and 39 (closing brace) in the second line refer to the correct name.

We worked around this in our processing pipeline here getsentry/symbolic#786 but would be great to understand how is this exactly produced, how should we interpret this, and potentially fix (if one applies) this in future releases.

I was asked to do so, thus cc: @sigmundch

@kamilogorek
Copy link
Author

cc @Swatinem @loewenheim @marandaneto for visibility.

@marandaneto
Copy link

marandaneto commented May 23, 2023

@kamilogorek we can look at their own symbolicator source code:

source_map_stack_trace
source_maps
stack_trace
native_stack_traces

But let's wait for the Dart team to follow up since we already have a workaround.

@mraleph mraleph added the area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. label May 23, 2023
@sigmundch
Copy link
Member

Thanks for reaching out!

I'm curious to learn more about what does your symbolication service provides and whether it matches how we produce source-maps.

Our encoding of source-map was tailored for two use cases: local debugging and deobfuscation of production stack traces. Years ago we had a lot of symbol information that was never in use and we started noticing the tax (e.g. memory utilization on deobfuscation servers). As a result, today we use a frugal approach and only include symbol information if it supports known scenarios.

  • debugging: our goal was to include data to assist debugging on modern browsers with source maps. For this we tracked down precisely where browsers allow you to set breakpoints, and ensure those positions had a source-mapping associated with it. Debuggers were not using the original name almost entirely, so this use case didn't require that we add much in terms of original names.

  • deobfuscation: our goal was to add data to deobfuscate error messages and stack traces produced in production. Here we do use a lot of symbol information. That said, standard source-maps were not sufficient. We designed custom extensions to fill the gap. This includes:

    • minified name data - used to convert names of static and instance members that appear in error messages, where no location context is available
    • inlinind data - used to expand one JavaScript frame into many Dart frames whenever our compiler inlines method calls.

We hope that one day source-maps will consider incorporating some of these extensions in the future into the standard, but that will take time. This is being tracked in tc39/ecma426#40

In terms of code - note that the links shared by @marandaneto are packages that make use of regular source-maps without our custom extensions. I'd recommend also looking at the dart2js deobfuscator. You'll see the use of the minified data where we translate error messages, and the use of the inline data in the logic mapping stack traces.

To address the specific question about the ( containing the mapping: there is a step in the deobfuscator that looks for the enclosing function to figure out the name. Long ago, dart2js used to produce ES5 code which contained the function keyword. We used this to identify the enclosing function and put the mapping to the original name there. Once we started emitting ES6 code, we decided to use the open parenthesis as the unique position where we located the start of the function. Our deobfuscator is tailored to find this position as well (see sourcemap_helper#L38).

@loewenheim
Copy link

At Sentry we try to resolve the scope a token is in and use that as the function name because the name is often something like apply with no further context. It appears in this situation that is exactly the wrong thing to do :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-dart2js
Projects
None yet
Development

No branches or pull requests

6 participants