-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Extract bundled files when IncludeAllContentForSelfExtract is set #42435
Conversation
Tagging subscribers to this area: @agocke |
@@ -204,7 +204,7 @@ void extractor_t::extract_new(reader_t& reader) | |||
begin(); | |||
for (const file_entry_t& entry : m_manifest.files) | |||
{ | |||
if (entry.needs_extraction()) | |||
if (m_manifest.is_netcoreapp3_compat_mode() || entry.needs_extraction()) |
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 looks like there are a number of other places in this file that are wrong (locate
, et al). I think a safer approach than trying to modify all the use sites is to have file_entry_t::read
take an extra force_extract
parameter, then pass it through to each file_entry_t
constructor and store it in a field. Then we can check the field in needs_extraction
and avoid changing all the call sites
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.
Agreed - the problem is everywhere we call entry.needs_extraction
, so it would be easier to bake it into the needs_extraction
itself. It would feel cleaner if we stored something like extracted
on each file entry.
.Should() | ||
.Pass() | ||
.And | ||
.HaveStdOutContaining("Hello World"); |
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.
Any way we could also confirm that the assemblies are actually loaded from the extraction location and not the bundle? Perhaps by printing the result of Assembly.Location
or similar?
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.
We should definitely test for this.
I think we always set BUNDLE_PROBE
(regardless of 3.x compat mode), so bundle probing takes precedence during assembly loading - I could see some undesired behaviour happening as a result.
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 most recent changes bundle probe should return false for all queries - I checked that the runtime behavior in that case is the same as without bundle probe in the case of assembly resolution. Note that it's not the same in other cases - especially Environment.GetCommandLineArguments[0] should still return the .exe path, not the main .dll path.
I also checked all the other places in runtime where we somehow react to bundle probe, and they all look correct to me.
This also means we can still pass bundle probe to the runtime even in full-extract case as all files will be marked as extracted in that situation (so the probe should return false all the time). This might be benefitial as the runtime will still "know" it's single-file (we don't really use that knowledge today though). Improve the test to actually validate locally built binaries and add validation of TPA and framework assembly loading.
… into netCoreApp3Compat
I tested lot of cases around the APIs which behave in a different/interesting way in single-file cases - AFAIK the behavior is as expected now. That is - for 3.1 backcompat, almost all APIs behave as non-single, with a couple of exceptions. @elinor-fung @agocke could you please take a second look? |
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 AssemblyBinder::BindToSystem
, if the bundle probe doesn't return a valid location, we expect System.Private.CoreLib.dll
to be in the runtime's directory - won't that be problematic for platforms like Linux where the runtime is linked into the host?
almost all APIs behave as non-single, with a couple of exceptions
Can we make sure we have a list somewhere in comments and for doc?
...aller/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/NetCoreApp3CompatModeTests.cs
Outdated
Show resolved
Hide resolved
...aller/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/NetCoreApp3CompatModeTests.cs
Outdated
Show resolved
Hide resolved
...aller/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/NetCoreApp3CompatModeTests.cs
Outdated
Show resolved
Hide resolved
...aller/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/NetCoreApp3CompatModeTests.cs
Outdated
Show resolved
Hide resolved
Re: testing - not sure if this has already been done or how simple it would be, but it might be interesting to grab a known consumer of 3.x single-file and try building/running it against 5.0 with this backcompat property. I remember Greenshot being a common reporter of issues with single-file in 3.x |
@elinor-fung You're correct that this is broken on Linux due to not finding CoreLib. Unfortunately this is a bigger issue: CoreLib's path is derived from the system path. I can see several possible ways to "fix" this:
If I could get any solution for free I would pick the last one - go back to exactly how 3.1 did it, but that's very expensive and introduces lot of differences in behavior in 5.0. |
Yet another possible solution would be to hardcode CoreLib into the bundle such that the probe always returns true for CoreLib (even if it's extracted onto disk) - the downside is that corelib would be memory-loaded so without Location and so on - less compatible. |
Candidate fix for the CoreLib issue on Linux - passing system path from host approach: It works well on Linux - also works on Windows (since it will sue the same codepath on Windows as well for consistency). |
This is the most compatible solution. It would be my top pick. Note that it will also address all not-yet-known issues where the true single file is breaking layout assumptions hardcoded in components out there (e.g. debugger?). The next best solution that I can think of is to extract the CoreLib path from |
Agreed. But, but yeah - the host build / packaging / sdk changes might be a bit expensive at this point. The CoreLib from |
I would fix just the CoreLib problem and leave the rest alone (for the 5.0 fix). The system directory concept is overloaded and it would be best to eliminate it. |
So I prepared a fix which adds a fallback to CoreLib search - if we don't find it in the bundle, nor "next" to the runtime, we will also look for it in TPA and use that path there. Tested it that it works in the single-file scenario on Linux. The change is not super clean as doing that would require non-trivial refactorings, so I avoided that. I just did the minimum to avoid too much code duplication. The general idea:
The change is here (didn't push it here to get some feedback on the approach first) @elinor-fung @jank could you please take a quick look if this approach sounds reasonable? |
Looks reasonable as release/5.0 fix. |
That seems reasonable for 5.0 |
Search for CoreLib in TPA
The other thing I found is that if there is no .deps.json file (e.g. |
Sad face... |
That said - I would be fine not supporting that case if it came down to it - it's such a niche thing ... I think |
Yeah, I'd also be fine not supporting it - seems like we'd have to special case where we load coreclr from and adding SPCL to the TPA in compat-mode... I think it is pretty niche as well, but we do talk about how loading works in our default dependency probing doc. |
The path must point to the extraction folder and not use the "fake" in-bundle path.
So the last commit should fix the .deps.json problem (had trouble with local setup, somehow everything got corrupted and I had to rebuild the entire repo again). That leaves only the no .deps.json case - I may look at that as well - since we know about it and the fix seems simple enough - we might as well. |
Actually we should be using path separator char in the APP_CONTEXT_DEPS_FILES, but that's something we won't be able to change really (too much chance of breaking something without too much value).
I tried the missing .deps.json case and it actually asserts in the host... pretty bad. I will probably look into this a little bit. |
@jkotas @janvorli @davidwrighton Would one of you have some time to do a last review here? |
Changes under src/coreclr/src look good to me. I have glanced over the rest and I did not find anything suspect, but I do not understand that part well. |
SString sDll(W(".dll")); | ||
SString sExe(W(".exe")); | ||
|
||
if (!dllOnly && (outPath.EndsWithCaseInsensitive(sNiDll) || |
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.
Why do we exclude the .ni.dll here? I wonder if that's correct.
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 dllOnly
is currently only set to true
when searching for System.Private.CoreLib (in the added fallback logic), so I believe the handling of it was more targeted to avoiding extra work in that scenario of just looking for .dll and not .ni.dll. For longer term / 6.0, I expect it will be refactored away per #42435 (comment).
@janvorli Any more comments? |
@agocke no, I don't. Things look reasonable, but I am not much familiar with the code being updated. |
Understandable, thanks for the input! @vitek-karas @mateoatr @elinor-fung Ready to merge? |
I read through it once more - looks good to me. |
Looks good to me as well. |
|
/backport to release/5.0 |
Started backporting to release/5.0: https://github.com/dotnet/runtime/actions/runs/281381356 |
@agocke backporting to release/5.0 failed, the patch most likely resulted in conflicts: $ git am --3way --ignore-whitespace --keep-non-patch changes.patch
Applying: Extract bundled files when IncludeAllContentForSelfExtract is set
Applying: Don't pass bundle probe to the runtime for netcoreapp3 compat mode
error: sha1 information is lacking or useless (src/installer/corehost/cli/bundle/file_entry.h).
error: could not build fake ancestor
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0002 Don't pass bundle probe to the runtime for netcoreapp3 compat mode
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Error: The process '/usr/bin/git' failed with exit code 128 Please backport manually! |
…tnet#42435) Backport of dotnet#42435 to release/5.0. (cherry picked from commit 0be66cb)
Fixes #42352