|
/**
|
|
* Copyright © 2019, Oracle and/or its affiliates. All rights reserved.
|
|
*
|
|
* Licensed under the Universal Permissive License v 1.0 as shown at
|
|
* http://oss.oracle.com/licenses/upl
|
|
*
|
|
*/
|
|
#include "fdleak.h"
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/resource.h> // for getrlimit, rlimit, RLIMIT_NO...
|
|
|
|
// File descriptor leak check
|
|
static size_t n_open_fds_at_start = 0;
|
|
enum { OFAS_SIZE = 100 };
|
|
enum { CHECK_FD_LIMIT = 1024 };
|
|
static int open_fds_at_start[OFAS_SIZE];
|
|
static int fd_is_open(int fd) {
|
|
// Use fcntl F_GETFL to figure out if file is open
|
|
return fcntl(fd, F_GETFL) != -1;
|
|
}
|
|
void find_open_fds_at_start(void) {
|
|
struct rlimit rlim;
|
|
if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
|
|
fprintf(stderr, "FATAL: getrlimit() failed\n");
|
|
abort();
|
|
}
|
|
for (int fd = 0; fd < (int)rlim.rlim_cur && fd < CHECK_FD_LIMIT; ++fd) {
|
|
if (fd_is_open(fd)) {
|
|
if (n_open_fds_at_start < OFAS_SIZE) {
|
|
open_fds_at_start[n_open_fds_at_start++] = fd;
|
|
} else {
|
|
fprintf(stderr, "FATAL: too many open_fds_at_start %zd\n",
|
|
n_open_fds_at_start);
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int fd_was_open(int fd) {
|
|
for (size_t i = 0; i < n_open_fds_at_start; ++i) {
|
|
if (fd == open_fds_at_start[i]) {
|
|
return !!1;
|
|
}
|
|
}
|
|
return !!0;
|
|
}
|
|
|
|
void fdleak_check(void)
|
|
{
|
|
struct rlimit rlim;
|
|
if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
|
|
fprintf(stderr, "FATAL: getrlimit() failed\n");
|
|
abort();
|
|
}
|
|
|
|
for (int fd = 0; fd < (int)rlim.rlim_cur && fd < CHECK_FD_LIMIT; ++fd) {
|
|
if (!fd_was_open(fd) && fd_is_open(fd)) {
|
|
fprintf(stderr, "BUG: fd %d still open at end of program\n", fd);
|
|
}
|
|
}
|
|
}
|