-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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 relative paths in wasm backend source maps. Fixes #9837 #9882
Conversation
tools/wasm-sourcemap.py
Outdated
@@ -263,7 +263,7 @@ def build_sourcemap(entries, code_section_offset, prefixes, collect_sources): | |||
if column == 0: | |||
column = 1 | |||
address = entry['address'] + code_section_offset | |||
file_name = entry['file'] | |||
file_name = os.path.relpath(entry['file']) |
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'm not sure this is correct: it uses a path relative to the current directory, but browsers / spec expect sources
to be relative to the source map file.
For example, consider case like following:
$ emcc ./temp.c -g4 -o dist/temp.wasm
Currently this produces a source map dist/temp.wasm.map
with following contents:
{"version":3,"sources":["./temp.c"],...
But this is incorrect, because temp.c
is actually in a folder up and needs to be referenced as ../temp.c
.
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.
In this case wouldn't the user need to set up --source-map-base
to fix that? But I've never really understood any of this stuff, hopefully you do...
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.
So --source-map-base
helps browser to find a source map from WebAssembly module.
But once browser found that source map, it now needs to find source files. There are three potential ways for it to do that:
sources
are specified as absolute URLs (not great for local files, but can work well enough for public libs).sources
are specified as relative URLs to the source map itself.- Source map contains
sourceRoot
, and then allsources
are relative to that instead (could be used in our case as an alternative, but it's a bit more complicated IMO).
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.
Actually, maybe you're right, and in this case --source-map-base
might be enough, at least if .wasm.map
is always emitted alongside .wasm
. Hmm...
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.
No, wait, scratch that, because relative URL still has to be relative to the source map itself. So the comment before still stands :)
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 browser is basically doing:
- Extract
sourceMappingURL
from the WebAssembly module (this one is{--source-map-base}/out.wasm.map
). - Load that source map.
- If that source map contains
sourceRoot
, prepend it to each item insources
. - Resolve each item in
sources
relative tosourceMappingURL
.
So we need each item in sources
to be relative to out.wasm.map
, no matter where it is.
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.
Thanks! I think I see a little better. I'm still confused about how that sourceMappingURL
option is used in two places for seemingly different purposes, though?
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.
In both places it's used as "URL of the .wasm.map". First, to find the map, and later to resolve other files it references, but semantic meaning is the same.
It's similar to how most module systems work, too: if A imports B, and B imports C, then first B is found from A, and then reference to C is resolve relatively to B.
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.
Needs to resolve relative path to a source map.
Those last commits should fix the test failures, at least the ones I ran locally. I had to change some tests, which I think was correct, but please take a look at those as I'm not sure. |
Ok, tests look good! |
tools/wasm-sourcemap.py
Outdated
@@ -264,6 +264,14 @@ def build_sourcemap(entries, code_section_offset, prefixes, collect_sources): | |||
column = 1 | |||
address = entry['address'] + code_section_offset | |||
file_name = entry['file'] | |||
# prefer to emit a relative path to the base path, which is where the |
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'm not sure if we should do anything special here... since we're talking about edge cases anyway, consider one where a static server that is hosting /
directory under, say, http://somedomain/static/
.
Then, let's say Wasm is under /dist/temp.wasm
on the disk (corresponding to URL: http://somedomain/static/dist/temp.wasm
on server), and source is under /src/temp.c
(URL: http://somedomain/static/src/temp.c
).
If you use relative paths, then source would be encoded as ../src/temp.c
and resolve correctly in URL context, but if you keep it as-is, then it would be encoded as /src/temp.c
and resolve to http://somedomain/src/temp.c
in browser, which is invalid.
TL;DR - let's just do the simple thing and use relative paths unconditionally, which would happen to also cover edge cases more correctly.
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.
That would break the current other.test_wasm_sourcemap
test, it gets this as the source file location:
"wasm-src://../../emscripten/tests/other/wasm_sourcemap/no_main.c"
Is that ok?
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.
(if that's not ok, what would the proper output there be, do you think?)
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 see, interesting. Where is wasm-src://
added? We probably should skip resolving relative paths altogether when that option is enabled.
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.
It's added in the test, using the --prefix
flag to the source map tool (which I don't understand well).
Maybe we can remove that option? If you and @yurydelendik agree that should be fine as I don't see other users in the codebase.
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.
@yurydelendik Doesn't -fdebug-prefix-map
in Clang change DWARF paths in-place to the remapped locations? If it does, then what is the role of custom --prefix
handling?
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 the role of custom --prefix handling
To do it after the fact of creating a wasm binary. (-fdebug-prefix-map
did not work in rustc at the moment of writing wasm-sourcemap.py)
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.
Sure, but now that both compilers support native remapping, it seems that we can just skip it here?
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.
the --base_path
logic is a really narrow case of the --prefix
. The former assumes that sources folders will have the same directory structure when published and calculates replacement part automatically, the latter provides more flexibility. FWIW they can exist together (by adding else:
for prefixes.sources.resolve
line). Sorry, I cannot provide more definite "yes, let's remove it", since I accustomed to the --prefix
way. :)
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.
Thanks @RReverser , you are right, I had that mixed up! Should be correct now - use the prefixes if provided, otherwise use a proper relative path.
Ah, some other tests now break. There is still the question of what to do with "bad" relative paths. For example, if I am in |
Yes - I described the difference for precisely same case in above comment thread #9882 (comment). TL;DR 2 - UPD: Note that this works in cases where entire UPD 2: Also probably worth testing what happens with Windows files on different disks. |
On a second thought, I suppose these cases are actually rare, so maybe we can just print error in case of sources and output on different root folders and/or Windows disks? Sounds like this would solve our final problems. |
Thanks @RReverser , I updated the lsan tests to accept those relative paths then. I agree just showing an error might be another reasonable path here, but I'm not sure how best to explain to users what to do in the error message, seems nontrivial - I'd rather leave that to followup work if we see it's necessary in practice, with people hitting this issue. |
@kripken OK, makes sense to me. |
I think I'm going to revert this so we can get a green build over the weekend. |
…mscripten-core#9925) After emscripten-core#9882 we don't always call .resolve, so the path normalization must be pulled into a place that dominates all code paths.
No description provided.