Description
Bug description
There are certain directories that cause the fs::read_dir
iterator (ReadDir
) to loop indefinitely. While I am not sure what the exact properties of these directories are, I know that they do appear in /proc
in the presence of zombie processes.
Consider the following Rust program ...
use std::env;
use std::fs;
fn main() {
let path = env::args().nth(1).unwrap();
for entry in fs::read_dir(path).unwrap() {
println!("{:?}", entry);
}
}
... and a zombie process with process id $ZOMBIE_PID
(see below how to create a zombie process on purpose). Running the above program with:
cargo run -- /proc/$ZOMBIE_PID/net
results in an infinite loop, printing:
Err(Os { code: 22, kind: InvalidInput, message: "Invalid argument" })
Err(Os { code: 22, kind: InvalidInput, message: "Invalid argument" })
Err(Os { code: 22, kind: InvalidInput, message: "Invalid argument" })
...
How to create a zombie process to reproduce this?
- Copy the code from https://stackoverflow.com/a/25228579/704831 into a file called
zombie.c
- Compile it
gcc -o zombie zombie.c
- Run it:
./zombie
- Get the PID of the "defunct"/zombie process:
ps -ef | grep '<defunct>'
Analysis
I did some debugging and I believe I found the cause of this.
When called on /proc/$ZOMBIE_PID/net
, the readdir_r
(3) function
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
returns error code 22
and - at the same time - returns NULL
in *result
, signalling the end of the directory stream.
If I am reading the code in the standard library correctly, this case can not be handled properly at the moment:
Code from the next
function of impl Iterator for ReadDir
:
rust/src/libstd/sys/unix/fs.rs
Lines 252 to 262 in f25c228
To handle this properly (without looping forever), one would probably have to check for entry_ptr.is_null()
in the first (Some(Err(...))
) case as well. The result (whether or not it returned a NULL
pointer) would probably have to be stored in some internal state of the iterator. On the forthcoming next
call, the iterator could then return None
.
Meta
> rustc --version
rustc 1.25.0 (84203cac6 2018-03-25)
> uname -s -r -v -m -p -i -o
Linux 4.16.7-1-ARCH #1 SMP PREEMPT Wed May 2 21:12:36 UTC 2018 x86_64 unknown unknown GNU/Linux