-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
sys::fs::status can fail on Windows with unexpected permission_denied
error code
#89137
Comments
I do find this to be a nicer solution as we are more precisely able to identify the scenario rather than guessing. I expect that ntdll.dll to be mapped in, so the additional linkage shouldn't be too expensive, but I know that @aganea did prefer to minimise the dependencies. |
Yes it is already mapped at runtime through My understanding is that One thing I dislike maybe with the above diff is that if I suppose we could either return a new type Also, the call to |
Isn't this true generally? In that there will always be a window between the return of status and the call to create file in which another process could have done something that would cause create file to fail? Though, I appreciate this is probably uncommon in practice and this patch would increase the likelihood of this case.
This seems reasonable. I'd expect that window to be small, so the call is likely to succeed in a few iterations (or there's an actual error). I'll give this a try and make sure that assumption is true.
Hmm good point. I never encountered this in my testing. |
I like the idea of using The only way I can see this going wrong is if a program checks for existence, gets file-not-found, and then proceeds to attempt to create a file at this location rather than attempting a different file name. However, such a program should recover from failing to create a unique file anyway after the file creation attempt, so that's not a big concern. |
I think I also would favour I wonder if @cjacek have any wisdom to share here, about what's portable in practice and what's not, when it comes to constructs like these. |
Generally yes, I think that
(Wine is based on black box testing, so the actual Windows code almost surely looks different, but externally observed behavior should match; compatibility varies between functions, but this one is extremely popular, so it's pretty well tested and it's relatively safe to assume that Windows is similar enough). BTW, the delay in deletion comes from Windows semantic that the file is not removed as long as any process has any handle to the file still open, so it may be postponed indefinitely. (And when the last handle is closed, I'd expect deletion to be reflected in VFS immediately, without an additional time window when no handles are opened but file still being considered as in a process of removing, but I didn't test that to confirm). |
Thank you so much for the insight! I'll switch to using |
I hit a snag here: the |
I would assume the error occurs on this line? https://github.com/apple/llvm-project/blob/next/clang/lib/Index/IndexUnitWriter.cpp#L247 With the domain knowledge, the
That error could mean other things, like "I don't have ACL permissions to access that file" but regardless there's nothing more that this process can do in that case. Now like you suggest, we could check It feels overall that there's a higher level synchronization mechanism missing in the index generation. The process that wants to write the unit should acquire a global mutex/named semaphore, to advertise other processes that it is writing that unit, and others should not attempt to write it. Getting back to |
Yes, that is the line in question and your patch would work. This is similar to swiftlang#8577, although returning I'm hesitant about the second interpretation of the error:
It's true that there's nothing else the process could do here, but this error condition should probably be fatal, unlike the ambiguous I agree it's not great to mislead consumers by reporting that the file is deleted when it is not, especially when it may never be deleted due to a stuck process or similar. Looping in I will prepare a patch with the looping solution returning a new To summarize the potential solutions:
As a note on |
If a delete is pending on the file queried for status, a misleading `permission_denied` error code will be returned (this is the correct mapping of the error set by GetFileAttributesW). By querying the underlying NTSTATUS code via ntdll's RtlGetLastNtStatus, this case can be disambiguated. If this underlying error code indicates a pending delete, fs::status will return a new `pending_delete` error code to be handled by callers Fixes #89137
If a delete is pending on the file queried for status, a misleading `permission_denied` error code will be returned (this is the correct mapping of the error set by GetFileAttributesW). By querying the underlying NTSTATUS code via ntdll's RtlGetLastNtStatus, this case can be disambiguated. If this underlying error code indicates a pending delete, fs::status will return a new `pending_delete` error code to be handled by callers Fixes llvm#89137 (cherry picked from commit cb7690a)
This is another instance of the same root cause of #83046
On Windows, if a file is queried with
GetFileAttributesW
after it has been marked for deletion (but not yet deleted), the query will fail with the error code being set toERROR_ACCESS_DENIED
.Apple's symbol index generation code writes index unit files out with temporary names, and then calls
rename
to place the file in the final location. Multiple clang processes may produce the same index unit file, and they race to write the file out to the final destination (overwriting is okay, because the unit file is the same). But before generating index information, the final destination file is first checked to see if it's up-to-date which would avoid doing work to generate duplicate information. This check is done by callingfs::status
on the final destination file, and if this occurs while another clang process has just called to rename its temporary index file to the final destination file, there is a small window where the destination file is marked for deletion andfs::status
returns an unexpectedpermission_denied
error.Ideally, I think the
status
function should detect this case on Windows and returnfile_not_found
instead ofpermission_denied
, but I initially had trouble finding a way to do this. I filed swiftlang#8577 to treatpermission_denied
asfile_not_found
in this specific case (which fixes the build failures), but this solution is not very satisfying in that it leaks Windows-specific idiosyncrasies.However, a colleague pointed out that the underlying
NTSTATUS
code actually does disambiguate this case with0xC0000056 STATUS_DELETE_PENDING
(which is mapped to Win32ERROR_ACCESS_DENIED
). Querying this error code is not super straightforward (at least I couldn't find a straightforward way), but I was able to identify and predicate on this case in Windows-specific code with the following patch:I prefer this solution to the alternative because the additional complexity is nicely encapsulated, but it is not without caveats, namely having to link
ntdll
and a lack of confidence in compatibility w.r.tRtlGetLastNtStatus
(I couldn't find any Microsoft documentation on this function).Maybe I'm missing something and there's an easy way to inspect this error code? Is the cost of this solution as it stands too high?
cc @compnerd
The text was updated successfully, but these errors were encountered: