You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Original bug ID: 5258 Reporter: toots Assigned to:@damiendoligez Status: closed (set by @damiendoligez on 2011-06-10T17:15:55Z) Resolution: fixed Priority: normal Severity: major Version: 3.12.0 Fixed in version: 3.12.1+dev Category: ~DO NOT USE (was: OCaml general) Monitored by: ripoche smimram
Bug description
The data structure for fd type in win32unix is the following:
struct filedescr {
union {
HANDLE handle;
SOCKET socket;
} fd; /* Real windows handle /
enum { KIND_HANDLE, KIND_SOCKET } kind;
int crt_fd; / C runtime descriptor /
unsigned int flags_fd; / See FLAGS_FD_* */
};
Win32 has a different API for opening files with a compatibility layer for code using the ususal fopen etc.. API.
By default, in win32unix, files are opened using windows' API, that is the function CreateFile. Accordingly, crt_fd is set to NO_CRT_FD, which indicates that there is not C runtime descriptor existing for now.
If later a C runtime descriptor is required, which is the case for instance when convering a Unix.fd to an in_channel, then the following function is used:
int win_CRT_fd_of_filedescr(value handle)
{
if (CRT_fd_val(handle) != NO_CRT_FD) {
return CRT_fd_val(handle);
} else {
int fd = _open_osfhandle((long) Handle_val(handle), O_BINARY);
if (fd == -1) uerror("channel_of_descr", Nothing);
return fd;
}
}
This function calls _open_osfhandle, which returns a C runtime descriptor from a regular windows file handle.
The problems occurs when trying to close the file, which is handled by the following function:
CAMLprim value unix_close(value fd)
{
if (Descr_kind_val(fd) == KIND_SOCKET) {
if (closesocket(Socket_val(fd)) != 0) {
win32_maperr(WSAGetLastError());
uerror("close", Nothing);
}
} else {
if (! CloseHandle(Handle_val(fd))) {
win32_maperr(GetLastError());
uerror("close", Nothing);
}
}
return Val_unit;
}
The issue here is that if a C runtime descriptor has been previously obtained, then using CloseHandle to close the file leaks the associated C runtime descriptor.
As a consequence, if too many file descriptors are leaks this way, then all subsequent functions used to get a C runtime descriptor will fail with a "too many opened files" error.
The issue is made even more obscur by the fact that, in this situation, the OS does not report those leaks in the list of opened files, because the underlying native file handle has indeed been closed properly...
Attached is a file (test_open.ml) that can be used to reproduce the issue. If one uncomments the call to Unix.in_channel_of_descr then the program fails after 2046 iterations (here) with the following error:
The solution to this issue is to close the file using _close when a C runtime descriptor is present. According to the documentation, this also close the underlying native file handle:
"To close a file opened with _open_osfhandle, call _close. The underlying handle is also closed by a call to _close, so it is not necessary to call the Win32 function CloseHandle on the original handle." http://msdn.microsoft.com/en-us/library/bdts1c9x.aspx
Therefore, I am also attaching a patch that implements those changes. With these patches, the test_open.ml program works.
Original bug ID: 5258
Reporter: toots
Assigned to: @damiendoligez
Status: closed (set by @damiendoligez on 2011-06-10T17:15:55Z)
Resolution: fixed
Priority: normal
Severity: major
Version: 3.12.0
Fixed in version: 3.12.1+dev
Category: ~DO NOT USE (was: OCaml general)
Monitored by: ripoche smimram
Bug description
The data structure for fd type in win32unix is the following:
struct filedescr {
union {
HANDLE handle;
SOCKET socket;
} fd; /* Real windows handle /
enum { KIND_HANDLE, KIND_SOCKET } kind;
int crt_fd; / C runtime descriptor /
unsigned int flags_fd; / See FLAGS_FD_* */
};
Win32 has a different API for opening files with a compatibility layer for code using the ususal fopen etc.. API.
By default, in win32unix, files are opened using windows' API, that is the function CreateFile. Accordingly, crt_fd is set to NO_CRT_FD, which indicates that there is not C runtime descriptor existing for now.
If later a C runtime descriptor is required, which is the case for instance when convering a Unix.fd to an in_channel, then the following function is used:
int win_CRT_fd_of_filedescr(value handle)
{
if (CRT_fd_val(handle) != NO_CRT_FD) {
return CRT_fd_val(handle);
} else {
int fd = _open_osfhandle((long) Handle_val(handle), O_BINARY);
if (fd == -1) uerror("channel_of_descr", Nothing);
return fd;
}
}
This function calls _open_osfhandle, which returns a C runtime descriptor from a regular windows file handle.
The problems occurs when trying to close the file, which is handled by the following function:
CAMLprim value unix_close(value fd)
{
if (Descr_kind_val(fd) == KIND_SOCKET) {
if (closesocket(Socket_val(fd)) != 0) {
win32_maperr(WSAGetLastError());
uerror("close", Nothing);
}
} else {
if (! CloseHandle(Handle_val(fd))) {
win32_maperr(GetLastError());
uerror("close", Nothing);
}
}
return Val_unit;
}
The issue here is that if a C runtime descriptor has been previously obtained, then using CloseHandle to close the file leaks the associated C runtime descriptor.
As a consequence, if too many file descriptors are leaks this way, then all subsequent functions used to get a C runtime descriptor will fail with a "too many opened files" error.
The issue is made even more obscur by the fact that, in this situation, the OS does not report those leaks in the list of opened files, because the underlying native file handle has indeed been closed properly...
Attached is a file (test_open.ml) that can be used to reproduce the issue. If one uncomments the call to Unix.in_channel_of_descr then the program fails after 2046 iterations (here) with the following error:
Running loop #2045
Opened file
Fatal error: exception Unix.Unix_error(15, "channel_of_descr", "")
The solution to this issue is to close the file using _close when a C runtime descriptor is present. According to the documentation, this also close the underlying native file handle:
"To close a file opened with _open_osfhandle, call _close. The underlying handle is also closed by a call to _close, so it is not necessary to call the Win32 function CloseHandle on the original handle."
http://msdn.microsoft.com/en-us/library/bdts1c9x.aspx
Therefore, I am also attaching a patch that implements those changes. With these patches, the test_open.ml program works.
File attachments
The text was updated successfully, but these errors were encountered: