The above code is basically broken, as dir1.close closed the file
descriptor. The subsequent dir2.close call is undefined behavior.
When run in isolation, it raises Errno::EBADF after the change, but
if another thread opens a file descriptor between the dir1.close
and dir2.close calls, the dir2.close call could close the file
descriptor opened by the other thread. Raising an exception is much
better in this case as it makes it obvious there is a bug in the code.
For the readdir check, since the GVL has already been released,
reacquire it rb_thread_call_with_gvl if an exception needs to be
raised.
Due to the number of closedir calls, this adds static close_dir_data
and check_closedir functions. The close_dir_data takes a
struct dir_data * and handles setting the dir entry to NULL regardless
of failure.
Add error checking to readdir, telldir, and closedir calls in dir.c
Raise SystemCallError exception when these functions return an error.
This changes behavior for the following case (found by the tests):
The above code is basically broken, as
dir1.close
closed the filedescriptor. The subsequent
dir2.close
call is undefined behavior.When run in isolation, it raises Errno::EBADF after the change, but
if another thread opens a file descriptor between the
dir1.close
and
dir2.close
calls, thedir2.close
call could close the filedescriptor opened by the other thread. Raising an exception is much
better in this case as it makes it obvious there is a bug in the code.
For the readdir check, since the GVL has already been released,
reacquire it rb_thread_call_with_gvl if an exception needs to be
raised.
Due to the number of closedir calls, this adds static close_dir_data
and check_closedir functions. The close_dir_data takes a
struct dir_data * and handles setting the dir entry to NULL regardless
of failure.
Fixes [Bug #20586]
Co-authored-by: Nobuyoshi Nakada [email protected]