-
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
Problem in File.Copy (and possibly elsewhere) on Linux #111807
Comments
Tagging subscribers to this area: @dotnet/area-system-io |
I believe the runtime/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs Lines 130 to 164 in c1ed07c
The return value from the runtime/src/native/libs/System.Native/pal_io.c Lines 343 to 346 in c1ed07c
|
runtime/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs Lines 130 to 164 in c1ed07c
That's in ReleaseHandle(). runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs Line 267 in 03b2d3d
This boolean result is ignored? |
Ah, you are right, it is really ignored there. I'll let owners of this code comment on this then. |
Description
System.IO.File.Copy(source_string, dest_string) has been observed to return success but leave corrupt data in the destination file.
dotnet 8.0.110, Ubuntu 22.04.5 LTS, x64.
Hypothesis
runtime/src/libraries/System.Private.CoreLib/src/System/IO/File.cs
Line 56 in 03b2d3d
sets up destination file handle here
runtime/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Unix.cs
Line 47 in 03b2d3d
CopyFile then proceeds operating on the destination file handle. Various syscalls to write() are issued and succeed. (Note source and destination are on different filesystems, so no CopyFileRange. Unclear if relevant.)
No fsync is issued.
Disposal of the destination file handle then happens. I think this calls through to
runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs
Line 267 in 03b2d3d
https://man7.org/linux/man-pages/man2/close.2.html says
And follows up with
We've definitely seen in the wild with NFS that:
strace and deliberately injecting faults leads me to the above.
This is only happening to a diminishingly small amount of operations, it isn't the case that my network or disks are entirely screwed. It's just that when it does happen - a few MB every PB of writes in my repro - data is bad and the application can't tell.
Reproduction Steps
System.IO.File.Copy("input",
"output");And something like the following, compiled and bashed in with LD_PRELOAD. All credit Copilot, all bugs mine.
`#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
typedef int (*orig_close_t)(int);
int close(int fd) {
static orig_close_t orig_close = NULL;
if (!orig_close) {
orig_close = (orig_close_t)dlsym(RTLD_NEXT, "close");
}
char path[1024];
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
}`
Or a variant on
strace -e trace=close -e fault=close:error=EIO -p <pid>
to achieve the same
Expected behavior
Either success and destination file has complete data, or failure reported to caller.
In the example above, that necessitates either not silently ignoring the close() call, or issuing an fsync beforehand.
Actual behavior
Silent data loss.
Regression?
No response
Known Workarounds
Can work around with lower level APIs, but "everyone" will use this one so it should probably be made safe.
Configuration
dotnet 8.0.110
Ubuntu 22.04.5 LTS
x64
Not believed specific to any of these
Other information
No response
The text was updated successfully, but these errors were encountered: