SingleFile bundles: Ensure extraction mappings are closed on Windows.#2272
SingleFile bundles: Ensure extraction mappings are closed on Windows.#22721 commit merged intodotnet:masterfrom
Conversation
There was a problem hiding this comment.
There's no License header for any of the test assets in https://github.com/dotnet/runtime/tree/master/src/installer/test/Assets/TestProjects
So, I kept the same pattern.
There was a problem hiding this comment.
Can you please fix that in a followup PR? Or at least create an issue for it.
There was a problem hiding this comment.
OK I'll fix it for all the projects in a subsequent PR.
There was a problem hiding this comment.
| if (map == NULL) | |
| if (address == NULL) |
There was a problem hiding this comment.
CloseHandle above may alter GetLastError. If that happens, the last error in the log will be bogus.
There was a problem hiding this comment.
Do you also need to close map handle before the function returns?
There was a problem hiding this comment.
There is no API to close a File Mapping. The UnMapViewOfFile documentation says:
"Although an application may close the file handle used to create a file mapping object, the system holds the corresponding file open until the last view of the file is unmapped. Files for which the last view has not yet been unmapped are held open with no sharing restrictions."
CreateFileMapping documentation says:
"Mapped views of a file mapping object maintain internal references to the object, and a file mapping object does not close until all references to it are released. Therefore, to fully close a file mapping object, an application must unmap all mapped views of the file mapping object by calling UnmapViewOfFile and close the file mapping object handle by calling CloseHandle. These functions can be called in any order."
Therefore, I think map handle cannot be closed; the sharing violation was because of the FileHandle.
There was a problem hiding this comment.
The documentation you have quoted says that you should close the map handle using CloseHandle.
You should close it even if it does not cause any obvious problem like sharing violation. It is good practice to avoid leaking resources.
There was a problem hiding this comment.
Thanks @jkotas. I misunderstood the text to mean that the mapping handle is automatically closed after all the references are unmapped. I've fixed it now.
47743ac to
dd4e9d3
Compare
c25ae8e to
8efa026
Compare
There was a problem hiding this comment.
Nitpick, but this could be written as:
if (address == nullptr)
{
trace::warning(...);
}
// ...
CloseHandle(file);
CloseHandle(map);
return address;(Slightly shorter code.)
There was a problem hiding this comment.
Nitpick: do we need string interpolation here? (Nevermind. This is just for testing, so it's OK.)
|
LGTM sans a nit. |
8efa026 to
071e047
Compare
|
Thanks @lpereira ; I've made the changes you suggested. |
1932524 to
75ef751
Compare
There was a problem hiding this comment.
Nit: It would make more sense to swap the order - we first open the file and then create the mapping, so closing them should be done in reverse order. Thus close the mapping first and then close the file. (I know it doesn't matter as the OS will do the right thing in both cases anyway).
There was a problem hiding this comment.
Can you please fix that in a followup PR? Or at least create an issue for it.
75ef751 to
4f45b06
Compare
When running a single-file app, the AppHost mmap()s itself in order to read its contents and extract the embedded contents. The Apphost must always map its contents in order to read the headers, but doesn't always extract the contents, because previously extracted files are re-used when available. In the case where apphost doesn't extract, the file mapping wasn't immediately closed on Windows. This prevents the app from being renamed while running -- an idiom used while updating the app in-place.
4f45b06 to
3fa15c9
Compare
|
Hello @swaroop-sridhar! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
|
@msftbot Squash and merge once testing succeeds. |
|
|
||
| public static string GetPublishedSingleFilePath(TestProjectFixture fixture) | ||
| { | ||
| return GetHostPath(fixture); |
There was a problem hiding this comment.
Do we really need a separate function for this if all it is calling is GetHostPath?
There was a problem hiding this comment.
I do think it is useful to have the wrapper call. In the single-file tests, we generate single-file apps in two ways:
- Through the SDK (dotnet publish /p:PublishSingleFile=true)
- Through invoking HostModel functions directly.
In the former case GetHostPath() will be the pre-bundled app, whereas in the later case, GetHostPath() will just be the host. So, I think it is easier to refer to them by different names.
Helps documenting the intent, and in searching for the use with different semantics.
There was a problem hiding this comment.
Ahh, okay. I didn't realize the different use cases and just assumed the paths in BundleHelper were for the pre-bundled app.
dotnet/runtime#1260 A single-file app cannot be renamed while running -- an idiom used while updating the app in-place. When running a single-file app, the AppHost reads itself in order to extract the embedded contents. The Apphost must always read its contents in order to read the headers, but doesn't always extract the contents, because previously extracted files are re-used when available. In the case where apphost doesn't extract, currently, the file stream isn't immediately closed on Windows. This prevents the app from being renamed while running. This change fixes the problem by closing the open stream in all cases. Very Low dotnet/runtime#2272
dotnet/runtime#1260 A single-file app cannot be renamed while running -- an idiom used while updating the app in-place. When running a single-file app, the AppHost reads itself in order to extract the embedded contents. The Apphost must always read its contents in order to read the headers, but doesn't always extract the contents, because previously extracted files are re-used when available. In the case where apphost doesn't extract, currently, the file stream isn't immediately closed on Windows. This prevents the app from being renamed while running. This change fixes the problem by closing the open stream in all cases. Very Low dotnet/runtime#2272
dotnet/runtime#1260 A single-file app cannot be renamed while running -- an idiom used while updating the app in-place. When running a single-file app, the AppHost reads itself in order to extract the embedded contents. The Apphost must always read its contents in order to read the headers, but doesn't always extract the contents, because previously extracted files are re-used when available. In the case where apphost doesn't extract, currently, the file stream isn't immediately closed on Windows. This prevents the app from being renamed while running. This change fixes the problem by closing the open stream in all cases. Very Low dotnet/runtime#2272
When running a single-file app, the AppHost mmap()s itself in order to read its contents and extract the embedded contents.
The Apphost must always map its contents in order to read the headers, but doesn't always extract the contents, because previously extracted files are re-used when available.
In the case where apphost doesn't extract, currently, the file mapping isn't immediately closed on Windows. This prevents the app from being renamed while running -- an idiom used while updating the app in-place.
This change fixes the problem by closing the open file-map.
Fixes #1260