-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Single file: Guard against partial cleanup of extracted files #3778
Comments
/cc @swaroop-sridhar |
@theimowski thanks for reporting the issue. If parts of the extraction directory are deleted, then it is bad for the single-exe app, because:
Were the files removed soon after the extraction (ex: the first run of the app failed) or several hours/days after the extraction? Several apps rely on the use of temporary files (ex: some msbuild targets), which may fail if files in the temp directory are arbitrarily deleted.
I'll look into this is 3.1 release.
I don't have a good explanation to this ... the assembly load logic may page in a few components (like custom assembly resolver etc) when it doesn't find a DLL. But I wouldn't expect the memory load to change significantly. |
The console application in question is a long-running process managed by another win32 service and is run on many windows devices (mostly desktop). |
@theimowski in your case, do you think setting the configuration DOTNET_BUNDLE_EXTRACT_BASE_DIR is a feasible alternative to handle the issue? Thanks. |
It seems to do the job yeah, will keep posted if we get reports of the issue again |
@swaroop-sridhar sorry i don't understand how this issue is related to the environment variable fix you suggested, we do not have anti virus on RedHat 7 and there is no cleanup script that is removing files either (unless the .net subsystem does some house keeping?). I saw the same issue few weeks ago on RedHat 7 and yesterday on windows. Can you please correct me with environment variable set, how this will mitigate the issue? Not really sure who is doing the partial cleanup here? Here is the issue i asked on stackoverflow, i should have reported here instead. The error i saw on linux was below, this issue is thus not limited to windows, it looks more like extraction issue.
As this is a show stopper (i am using it for trading system), I've decided to not package the runtime. |
I think what happened is that the files within Similarly, in your Linux run, I believe We're considering a service fix to re-extract the contents of the bundle on failure within the host. In the meantime, by setting |
Is this going to be fixed for 3.1? I heard that this was planned to have a partial fix in a servicing early 2020. While I can direct the installation for extraction, part of what is convenient is that it differentiates every build to it's own folder. I can just wrap it in an sfx to extract the archive and the user clicks it and runs. I can manually direct it but then the user can't simply double click my executable. |
@Mgamerz fix for this issue is under development; I expect this issue be fixed in the Feb or March servicing release. Thanks. |
I also have this issue of files missing in the .net tmp directory. I have a question about if a new version of the application is run and it will create another .\net\Application\RandomName Directory. What mechanism is in place to remove the old directory? As I have seen them them lingering around. |
@speed2048 the extraction directory is different for each build, in order to avoid inadvertent overwrite across app releases. There is no explicit removal for these directories. They are removed over time by the cleanup of the temp-directories. |
Thanks swaroop-sridar. In the current implementation what .net core process ( if it is a process ) removes these temp-directories over time? I can see disk space becoming an issue if you are testing self contained apps that can take between 70 - 90 Mb per version. |
+ Fix the flickering that could be seen in older versions while running a bot. + Add a help text for the `run-bot` command, listing the available options and when to use them. Regarding the contents of the zip-archive: At the moment, the app is distributed in several files, to avoid a bug in the single-exe file publishing functionality of .NET Core: + #3 (comment) + dotnet/core#3830 (comment) + https://github.com/dotnet/core-setup/issues/8314#issuecomment-574853663
@speed2048 there's no .net cleanup process. The cleanup is expected to be performed by the OS cleanup of temp-directories. Typically, the single-file publishing is not used during tight-loop development cycle; rather it is designed for publishing for deployment. |
Here is the proposed algorithm to solve this partial-cleanup problem:
All of the renames above should be done with appropriate retries to circumvent interference from anti-virus apps. |
|
By default,
The extraction of individual files to
Yes, removing/re-extracting to
I don't see the problem if multuple processes are trying to fixup There is no evidence that the temp-directory cleanup removes partial contents of files; so if a file exists in |
@swaroop-sridhar OK, makes sense. I do agree that "delete whole dir" is also problematic. And now reading it again, it's probably worse then updating it piece by piece. One note on that though: We need to document somewhere that the extraction process may add files to the folder. Basically if the app carries a file with it, which is later on deleted by the app - it will be recreated next time I run it. That behavior will not be observable on "debug builds", but only on the single-file builds. Vast majority of users won't run into this, but some might. It's basically the scenario where the app carries a config file with it and writes to it as user modifies settings. If that app can also delete such file... it would hit this problem (I'm in no way suggesting apps should have files like this as part of their install BTW). |
Thanks @vitek-karas. Yes these are good points to note in the documentation. They are not specific to the current fix -- if |
Has there been any discussion about a switch the developer could use that would tell the extraction to replace the previous extraction (e.g. remove the previous version(s) if they exist and use the new one/current one that's being executed). In cases where this is appropriate the developer could toggle this setting on publish and it would alleviate the issue of having 10 old versions (at 150MB a version) stored when only the newest one is wanted/needed. It wouldn't stop a user from using old versions but switching versions back and forth (rare case when people are typically using the most updated bundle) would take the extraction hit. |
Currently, there is no plan to support explicit removal of extraction directories. Removing extractions is tricky, because another process may be using them. It is very unlikely that the feature will be added to .net core 3.1 in servicing releases. So, the only cleanup currently is via tmp-directory cleanup by the OS. In .net 5, the amount of extracted files will be minimal (or none, depending on the app). So, there we can consider the design where every execution extracts to a temp-directory, and attempts to cleanup after its completion. However, due to various failure-modes in the app, the runtime may not always get a chance to cleanup the extraction. |
This change fixes #3778 This change is mainly targeted to be servicing fix for .net core 3.1. When executing single-file apps, if a pre-existing extraction exists, the contents of the extraction directory are now verified. If files are missing, they are recovered. **Extraction Algorithm** `ExtractionDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<bundle-id>` `WorkingDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<process-id>` If `ExtractionDir` does not exist, then Create `WorkingDir`, and extract bundle contents within it Attempt to rename `WorkingDir` as `ExtractionDir` If the rename succeeds, continue execution of the app If not, another process completed extraction; Verify and reuse this extraction (as in step 2). If `ExtractionDir` exists, then verify that it contains all files listed in the manifest. If all contents are available, Remove `WorkingDir` Continue execution of the app, reusing the contents. If certain files are missing within `ExtractionDir`, then For each missing file, do the following individually Extract the files within `WorkingDir` Create sub-paths within `ExtractionDir` if necessary Rename the file from `WorkingDir/path/<file>` to `ExtractionDir/path/<file>` unless `ExtractionDir/path/<file>` exists (extracted there by another process in the meantime) Remove `WorkingDir` Continue execution of the app. All of the renames above are done with appropriate retries to circumvent interference from anti-virus apps. **Startup time impact** * Console HelloWorld execution time: * Framework dependent app: Windows/Linux No measurable difference * Self-contained app: Windows: ~10ms additional * Self-contained app: Linux: No measurable difference * Greenshot Startup: * Self-contained Windows: No noticiable/measurable difference * NugetPackageExplorer Startup: * Self-contained Windows: No noticiable/measurable difference
A couple of things:
Thanks. |
Dotnet doesn't delete any extracted files. The default extraction directory is within the
In .net 5, the assemblies bundled in single file apps will be loaded directly from the bundle. The design for this feature is explained in this document. |
Thanks @swaroop-sridhar for adding the fix - do I understand correctly that the validation mechanism is run only upon start of the application? I.e. for long running processes, if some of the extracted files are deleted, one needs to restart the app to restore those files right? |
Yes, @theimowski, the extraction is only validated at startup. This is a potential risk for long running processes, but the files extracted in the temp directory are typically not lost for several months. |
… files ** Issue dotnet/runtime#3778 ** Customer Scenario Single-file apps rely on extractiong their contents to disk. The extaction is performed to a temp-directory by default, which may be cleaned up by the OS. The app can re-extract itself if the entire extraction is cleaned up -- but not partial deletions. Customers have noticed that for some apps, the extracted files were removed, but the extraction directory itself wasn't. This causes the app to fail to start. ** Problem When executing single-file apps, if a pre-existing extraction exists, it is assumed to be valid. ** Solution When executing single-file apps, if a pre-existing extraction exists, the contents of the extraction directory are now verified. If files are missing, they are recovered. **Extraction Algorithm** `ExtractionDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<bundle-id>` `WorkingDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<process-id>` If `ExtractionDir` does not exist, then Create `WorkingDir`, and extract bundle contents within it Attempt to rename `WorkingDir` as `ExtractionDir` If the rename succeeds, continue execution of the app If not, another process completed extraction; Verify and reuse this extraction (as in step 2). If `ExtractionDir` exists, then verify that it contains all files listed in the manifest. If all contents are available, Remove `WorkingDir` Continue execution of the app, reusing the contents. If certain files are missing within `ExtractionDir`, then For each missing file, do the following individually Extract the files within `WorkingDir` Create sub-paths within `ExtractionDir` if necessary Rename the file from `WorkingDir/path/<file>` to `ExtractionDir/path/<file>` unless `ExtractionDir/path/<file>` exists (extracted there by another process in the meantime) Remove `WorkingDir` Continue execution of the app. All of the renames above are done with appropriate retries to circumvent interference from anti-virus apps. ** Startup time impact * Console HelloWorld execution time: * Framework dependent app: Windows/Linux No measurable difference * Self-contained app: Windows: ~10ms additional * Self-contained app: Linux: No measurable difference * Greenshot Startup: * Self-contained Windows: No noticiable/measurable difference * NugetPackageExplorer Startup: * Self-contained Windows: No noticiable/measurable difference ** Risk Medium. The change is well scoped, but isn't trivial. It affects all single-file apps. ** Master Branch dotnet/runtime#32649
… files ** Issue dotnet/runtime#3778 ** Customer Scenario Single-file apps rely on extractiong their contents to disk. The extaction is performed to a temp-directory by default, which may be cleaned up by the OS. The app can re-extract itself if the entire extraction is cleaned up -- but not partial deletions. Customers have noticed that for some apps, the extracted files were removed, but the extraction directory itself wasn't. This causes the app to fail to start. ** Problem When executing single-file apps, if a pre-existing extraction exists, it is assumed to be valid. ** Solution When executing single-file apps, if a pre-existing extraction exists, the contents of the extraction directory are now verified. If files are missing, they are recovered. **Extraction Algorithm** `ExtractionDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<bundle-id>` `WorkingDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<process-id>` If `ExtractionDir` does not exist, then Create `WorkingDir`, and extract bundle contents within it Attempt to rename `WorkingDir` as `ExtractionDir` If the rename succeeds, continue execution of the app If not, another process completed extraction; Verify and reuse this extraction (as in step 2). If `ExtractionDir` exists, then verify that it contains all files listed in the manifest. If all contents are available, Remove `WorkingDir` Continue execution of the app, reusing the contents. If certain files are missing within `ExtractionDir`, then For each missing file, do the following individually Extract the files within `WorkingDir` Create sub-paths within `ExtractionDir` if necessary Rename the file from `WorkingDir/path/<file>` to `ExtractionDir/path/<file>` unless `ExtractionDir/path/<file>` exists (extracted there by another process in the meantime) Remove `WorkingDir` Continue execution of the app. All of the renames above are done with appropriate retries to circumvent interference from anti-virus apps. ** Startup time impact * Console HelloWorld execution time: * Framework dependent app: Windows/Linux No measurable difference * Self-contained app: Windows: ~10ms additional * Self-contained app: Linux: No measurable difference * Greenshot Startup: * Self-contained Windows: No noticiable/measurable difference * NugetPackageExplorer Startup: * Self-contained Windows: No noticiable/measurable difference ** Risk Medium. The change is well scoped, but isn't trivial. It affects all single-file apps. ** Master Branch dotnet/runtime#32649
… files ** Issue dotnet/runtime#3778 ** Customer Scenario Single-file apps rely on extractiong their contents to disk. The extaction is performed to a temp-directory by default, which may be cleaned up by the OS. The app can re-extract itself if the entire extraction is cleaned up -- but not partial deletions. Customers have noticed that for some apps, the extracted files were removed, but the extraction directory itself wasn't. This causes the app to fail to start. ** Problem When executing single-file apps, if a pre-existing extraction exists, it is assumed to be valid. ** Solution When executing single-file apps, if a pre-existing extraction exists, the contents of the extraction directory are now verified. If files are missing, they are recovered. **Extraction Algorithm** `ExtractionDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<bundle-id>` `WorkingDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<process-id>` If `ExtractionDir` does not exist, then Create `WorkingDir`, and extract bundle contents within it Attempt to rename `WorkingDir` as `ExtractionDir` If the rename succeeds, continue execution of the app If not, another process completed extraction; Verify and reuse this extraction (as in step 2). If `ExtractionDir` exists, then verify that it contains all files listed in the manifest. If all contents are available, Remove `WorkingDir` Continue execution of the app, reusing the contents. If certain files are missing within `ExtractionDir`, then For each missing file, do the following individually Extract the files within `WorkingDir` Create sub-paths within `ExtractionDir` if necessary Rename the file from `WorkingDir/path/<file>` to `ExtractionDir/path/<file>` unless `ExtractionDir/path/<file>` exists (extracted there by another process in the meantime) Remove `WorkingDir` Continue execution of the app. All of the renames above are done with appropriate retries to circumvent interference from anti-virus apps. ** Startup time impact * Console HelloWorld execution time: * Framework dependent app: Windows/Linux No measurable difference * Self-contained app: Windows: ~10ms additional * Self-contained app: Linux: No measurable difference * Greenshot Startup: * Self-contained Windows: No noticiable/measurable difference * NugetPackageExplorer Startup: * Self-contained Windows: No noticiable/measurable difference ** Risk Medium. The change is well scoped, but isn't trivial. It affects all single-file apps. ** Master Branch dotnet/runtime#32649
… files ** Issue dotnet/runtime#3778 ** Customer Scenario Single-file apps rely on extractiong their contents to disk. The extaction is performed to a temp-directory by default, which may be cleaned up by the OS. The app can re-extract itself if the entire extraction is cleaned up -- but not partial deletions. Customers have noticed that for some apps, the extracted files were removed, but the extraction directory itself wasn't. This causes the app to fail to start. ** Problem When executing single-file apps, if a pre-existing extraction exists, it is assumed to be valid. ** Solution When executing single-file apps, if a pre-existing extraction exists, the contents of the extraction directory are now verified. If files are missing, they are recovered. **Extraction Algorithm** `ExtractionDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<bundle-id>` `WorkingDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<process-id>` If `ExtractionDir` does not exist, then Create `WorkingDir`, and extract bundle contents within it Attempt to rename `WorkingDir` as `ExtractionDir` If the rename succeeds, continue execution of the app If not, another process completed extraction; Verify and reuse this extraction (as in step 2). If `ExtractionDir` exists, then verify that it contains all files listed in the manifest. If all contents are available, Remove `WorkingDir` Continue execution of the app, reusing the contents. If certain files are missing within `ExtractionDir`, then For each missing file, do the following individually Extract the files within `WorkingDir` Create sub-paths within `ExtractionDir` if necessary Rename the file from `WorkingDir/path/<file>` to `ExtractionDir/path/<file>` unless `ExtractionDir/path/<file>` exists (extracted there by another process in the meantime) Remove `WorkingDir` Continue execution of the app. All of the renames above are done with appropriate retries to circumvent interference from anti-virus apps. ** Startup time impact * Console HelloWorld execution time: * Framework dependent app: Windows/Linux No measurable difference * Self-contained app: Windows: ~10ms additional * Self-contained app: Linux: No measurable difference * Greenshot Startup: * Self-contained Windows: No noticiable/measurable difference * NugetPackageExplorer Startup: * Self-contained Windows: No noticiable/measurable difference ** Risk Medium. The change is well scoped, but isn't trivial. It affects all single-file apps. ** Master Branch dotnet/runtime#32649
… files ** Issue dotnet/runtime#3778 ** Customer Scenario Single-file apps rely on extractiong their contents to disk. The extaction is performed to a temp-directory by default, which may be cleaned up by the OS. The app can re-extract itself if the entire extraction is cleaned up -- but not partial deletions. Customers have noticed that for some apps, the extracted files were removed, but the extraction directory itself wasn't. This causes the app to fail to start. ** Problem When executing single-file apps, if a pre-existing extraction exists, it is assumed to be valid. ** Solution When executing single-file apps, if a pre-existing extraction exists, the contents of the extraction directory are now verified. If files are missing, they are recovered. **Extraction Algorithm** `ExtractionDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<bundle-id>` `WorkingDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<process-id>` If `ExtractionDir` does not exist, then Create `WorkingDir`, and extract bundle contents within it Attempt to rename `WorkingDir` as `ExtractionDir` If the rename succeeds, continue execution of the app If not, another process completed extraction; Verify and reuse this extraction (as in step 2). If `ExtractionDir` exists, then verify that it contains all files listed in the manifest. If all contents are available, Remove `WorkingDir` Continue execution of the app, reusing the contents. If certain files are missing within `ExtractionDir`, then For each missing file, do the following individually Extract the files within `WorkingDir` Create sub-paths within `ExtractionDir` if necessary Rename the file from `WorkingDir/path/<file>` to `ExtractionDir/path/<file>` unless `ExtractionDir/path/<file>` exists (extracted there by another process in the meantime) Remove `WorkingDir` Continue execution of the app. All of the renames above are done with appropriate retries to circumvent interference from anti-virus apps. ** Startup time impact * Console HelloWorld execution time: * Framework dependent app: Windows/Linux No measurable difference * Self-contained app: Windows: ~10ms additional * Self-contained app: Linux: No measurable difference * Greenshot Startup: * Self-contained Windows: No noticiable/measurable difference * NugetPackageExplorer Startup: * Self-contained Windows: No noticiable/measurable difference ** Risk Medium. The change is well scoped, but isn't trivial. It affects all single-file apps. ** Master Branch dotnet/runtime#32649
… files (#9013) ** Issue dotnet/runtime#3778 ** Customer Scenario Single-file apps rely on extractiong their contents to disk. The extaction is performed to a temp-directory by default, which may be cleaned up by the OS. The app can re-extract itself if the entire extraction is cleaned up -- but not partial deletions. Customers have noticed that for some apps, the extracted files were removed, but the extraction directory itself wasn't. This causes the app to fail to start. ** Problem When executing single-file apps, if a pre-existing extraction exists, it is assumed to be valid. ** Solution When executing single-file apps, if a pre-existing extraction exists, the contents of the extraction directory are now verified. If files are missing, they are recovered. **Extraction Algorithm** `ExtractionDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<bundle-id>` `WorkingDir` = `$DOTNET_BUNDLE_EXTRACT_BASE_DIR/<app>/<process-id>` If `ExtractionDir` does not exist, then Create `WorkingDir`, and extract bundle contents within it Attempt to rename `WorkingDir` as `ExtractionDir` If the rename succeeds, continue execution of the app If not, another process completed extraction; Verify and reuse this extraction (as in step 2). If `ExtractionDir` exists, then verify that it contains all files listed in the manifest. If all contents are available, Remove `WorkingDir` Continue execution of the app, reusing the contents. If certain files are missing within `ExtractionDir`, then For each missing file, do the following individually Extract the files within `WorkingDir` Create sub-paths within `ExtractionDir` if necessary Rename the file from `WorkingDir/path/<file>` to `ExtractionDir/path/<file>` unless `ExtractionDir/path/<file>` exists (extracted there by another process in the meantime) Remove `WorkingDir` Continue execution of the app. All of the renames above are done with appropriate retries to circumvent interference from anti-virus apps. ** Startup time impact * Console HelloWorld execution time: * Framework dependent app: Windows/Linux No measurable difference * Self-contained app: Windows: ~10ms additional * Self-contained app: Linux: No measurable difference * Greenshot Startup: * Self-contained Windows: No noticiable/measurable difference * NugetPackageExplorer Startup: * Self-contained Windows: No noticiable/measurable difference ** Risk Medium. The change is well scoped, but isn't trivial. It affects all single-file apps. ** Master Branch dotnet/runtime#32649
Just to make sure, this is not fixed in .net core 3.1 right? Some of our clients are running into this problem, it seems Windows or some other software clears their Temp folder in a weekly routine. |
3.1.4 has been updated, but there seems to be a new problem. If PublishReadyToRun is set to true, the program will report errors. When PublishReadyToRun is set to false, the program can run normally Err1: Err2: |
This issue is closed. Can you please open new issues? |
@yhnbgfd I think the failure you report is not related to this issue. Please file a different issue with more details about how to repro the problem. Thanks. |
Steps to reproduce
Unfortunately no deterministic steps to reproduce here, but we've experienced multiple cases of files getting removed from %TEMP%.net on windows.
The files that were locked by main executable were still there, but "casual" dlls and other files got removed either by AntiVirus or other software.
As a result when our long-running process tried to load files from the temp directory it failed to do so, and we even observed high memory consumption when that was the case.
As a workaround we now set the DOTNET_BUNDLE_EXTRACT_BASE_DIR variable to custom directory.
That said I think the %TEMP% directory is not a good default.
Expected behavior
The default extraction directory for Single File Publish should be "safe", meaning there's low risk other programs might try to remove stuff from there
Actual behavior
Antivirus and other software might remove files from the extraction directory
Environment data
Various flavours of Windows OS
The text was updated successfully, but these errors were encountered: