Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unix fd leak under windows #5258

Closed
vicuna opened this issue Apr 27, 2011 · 1 comment
Closed

Unix fd leak under windows #5258

vicuna opened this issue Apr 27, 2011 · 1 comment
Assignees
Labels

Comments

@vicuna
Copy link

vicuna commented Apr 27, 2011

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

@vicuna
Copy link
Author

vicuna commented Apr 28, 2011

Comment author: ripoche

This issue also affects 3.11.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants