-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[corlib] Fix sharing mode validation rules #16247
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
Conversation
Switching to corefx File.Copy on unix changed the behavior where it opened a source and destination stream in order to pass
the safe handles to Interop.Sys.CopyFile. This exposed a flaw in our sharing validation rules in MonoIO.Open, which
threw an exception in this scenario:
new FileStream("source.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 2048, FileOptions.DeleteOnClose);
new FileStream("source.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 2048, FileOptions.None);
The change is intended to take into account all sharing scenarios.
lambdageek
left a comment
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.
test looks good. fix makes sense. there's a line in the if that seems suspicious to me, but overall looks ok.
mono/metadata/w32file-unix.c
Outdated
| /* New share mode doesn't match up */ | ||
| mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Access mode prevents open: requested share: 0x%" PRIx32 ", file has access: 0x%" PRIx32, __func__, sharemode, file_existing_access); | ||
| if (file_existing_share != sharemode && | ||
| ((sharemode | FILE_SHARE_READ) != sharemode) && |
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 need this? It's checking that the new requested sharing mode sharemode doesn't include FileShare.Read. Why?
Isn't it enough to just check that file_existing_share != sharemode (new is different from existing) and (file_existing_share | sharemode) == file_existing_share (new it at most as lax as existing - it doesn't include). That together means that new sharemode is a strict subset of the existing file_existing_share. And therefore we take the branch and return FALSE.
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.
This change/code confuses me.
Why do the share modes have to line up, as long as they grant each other access?
Don't sharemodes get anded upon successful open, to weigh against later opens?
I might try it myself if that not too rude.
like:
- open read, share readwrite
- open read, share read; success, resulting share is read
- open readwrite; fail
or:
- open read, share read
- open read, share readwrite; success, resulting share is read
- open readwrite; fail
Note this cannot really work without underlying kernel support.
We end up presumably only enforcing it within the process, amongst mono users, which is a lot less than the original intent.
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.
@lambdageek From our conversation, the ((sharemode | FILE_SHARE_READ) != sharemode) && line is to close the gap w/ ReadWrite. Without it, FIle.Copy would fail (ReadWrite to Read).
The more I look at this and the corefx version, the more I think we should just follow in kind.
Which is, FileShare.None locks exclusively and that's about it.
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.
Yeah, since it requires kernel/filesystem to really support, i.e. to play "correctly" with non-mono callers.
A coworker of mine years ago suggested this sharing stuff, while it seems like a good idea, isn't really all that great even on Windows and perhaps is pointless. Unix might have its flaws, but this missing feature you don't hear about much.
My simple attempt broke tests.
#16271
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 check is pretty simple now.
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.
Need to "subscribe" to that file/line and get a notification if they decide to work on it.
Maybe the AI will notice the copied code or this comment and notify us, or update ours.
|
How soon can we get this into xamarin.android stable? It is broken since VS release 16.2 on production. |
1. If the caller specifies FileShare.None, then it's an exclusive lock and no sharing is allowed. 2. If the caller specifies some other FileShare option, then FileShare.None cannot be specified.
lambdageek
left a comment
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.
Ok, now we match what CoreFX does (FileShare.None is exclusive locking which is incompatible with any other open request for the same file; everything else is ok to share)
|
@monojenkins backport to 2019-08 |
|
@monojenkins backport to 2019-02 |
| #define GENERIC_EXECUTE 0x20000000 | ||
| #define GENERIC_ALL 0x10000000 | ||
|
|
||
| #define FILE_SHARE_NONE 0x00000000 |
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.
This is not actually a symbol in Windows, but ok.
|
@monojenkins build failed |
Fixes mono/mono#16032 When we switched to corefx File.Copy on unix, the behavior changed where it opened a source and destination stream in order to pass the safe handles to Interop.Sys.CopyFile. This exposed a flaw in our sharing validation rules in MonoIO.Open, which threw an exception in this scenario: new FileStream("source.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 2048, FileOptions.DeleteOnClose); new FileStream("source.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 2048, FileOptions.None); Simplified the FileShare check down to: 1. If the caller specifies FileShare.None, then it's an exclusive lock and no sharing is allowed. 2. If the caller specifies some other FileShare option, then FileShare.None cannot be specified. Commit migrated from mono/mono@da2c015
Fixes #16032
When we switched to corefx File.Copy on unix, the behavior changed where it opened a source and destination stream in order to pass the safe handles to Interop.Sys.CopyFile. This exposed a flaw in our sharing validation rules in MonoIO.Open, which threw an exception in this scenario:
This should now correctly line up w/ https://docs.microsoft.com/en-us/dotnet/api/system.io.fileshare?view=netframework-4.8#fields