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.
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.