Spontaneous file operation failure

My code logic like below, when running cargo test, it has spontaneous failure in canonicalize call below. Before calling it, I already check if the file exist, and it is strange how exists return true while canonicalize return error NotFound.

        let original_file_path = test_dir.join("testdb.persy");

        File::create(&original_file_path).unwrap();

        assert!(
            original_file_path.exists(),
            "Original file should exist before testing."
        );
       std::fs::canonicalize(&original_file_path.to_string_lossy())

Does std::fs::canonicalize(&original_file_path) also fail? If not, then my guess is that test_dir contains non-UTF-8 characters, and thus to_string_lossy is lossy.

this is a short version of code, we do printout the file path, it is not because to string lossy. The thing is exist return true, but canonicalize return io::NotFound error

You probably didn't understand the point behind @farnz 's question – NotFound would also be returned if a non-UTF-8 path would be converted to a string and back to a path, because that would change the path. I.e., there would be no file at the (wrong, lossily-converted) path.

Anyway, the code exhibits a classic TOCTOU race condition. There's no reason another process couldn't rename, move, or delete the file between the assert and the call to canonicalize. For this reason, you shouldn't ever write code like if exists { do file stuff }. It's simply incorrect. Whatever you want to do, attempt doing it, and detect/handle errors if the operation failed.

3 Likes

@paramagnetic "we do printout the file path", and we know it is utf-8 path when error happen.

one more thing, this happen when run cargo test, not in normal opertaions

even with RUST_TEST_THREADS=1 cargo test ?

1 Like

OS? Filesystem? Is the path absolute? Does it work without the to_string_lossy?

2 Likes

Run with debugger.

NotFound is a general error kind and likely not descriptive of the underlying OS error.
Call raw_os_error for that.

Maybe other tests are using the same file.

(shared mutable state, smh)

You can use something like tempdir to keep all the tests separate.

2 Likes

Thanks all for answers, sorry I did not provide all context in my questions.
I have found out the root cause is due to set_var which is unsafe in multi-thread although it is NOT makred as unsafe, but it will be, as the std docs warn it about the safety.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.