Windows: Is std::env::current_dir unsafe?

I think the standard library calls GetCurrentDirectoryW for std::env::current_dir. The Microsoft docs give the following warning:

Multithreaded applications and shared library code should not use the GetCurrentDirectory function and should avoid using relative path names. The current directory state written by the SetCurrentDirectory function is stored as a global variable in each process, therefore multithreaded applications cannot reliably use this value without possible data corruption from other threads that may also be reading or setting this value. This limitation also applies to the SetCurrentDirectory and GetFullPathName functions. The exception being when the application is guaranteed to be running in a single thread, for example parsing file names from the command line argument string in the main thread prior to creating any additional threads. Using relative path names in multithreaded applications or shared library code can yield unpredictable results and is not supported.

Does this not mean that it violates Rust’s safety rules?

1 Like

.net is supposed to be memory safe and it also calls GetCurrentDirectory without holding locks, so it should probably be fine and the documentation incorrect.

ReactOS holds the PEB lock across the whole implementation of GetCurrentDirectory and is thus safe, and I’d assume Microsoft Windows also does that.

1 Like

Ah, many thanks. It wouldn’t be the first time the Windows docs were wrong or outdated.

2 Likes

The thing is, if something else in the process changes the CWD, you’ll likely get erratic behavior anyway. That’s probably why Microsoft wrote that advice.

This is not a Windows-specific problem. But “corruption” here I think just means that if you do things like first checking current_dir and then doing something based on that check, you have a TOCTOU issue. There is no UB but your code is wrong.

2 Likes

I think I misinterpreted the docs then. The references to “global variable” and “data corruption” while other threads are “reading or setting” sounded a lot like accessing a mutable static without locks.

Maybe because I’d been thinking a lot about Rust’s safety at the time I read it.