diff --git a/dirent/Makefile b/dirent/Makefile index 556f759f65..f9056724f0 100644 --- a/dirent/Makefile +++ b/dirent/Makefile @@ -58,6 +58,7 @@ tests := \ bug-readdir1 \ list \ opendir-tst1 \ + tst-closedir-leaks \ tst-fdopendir \ tst-fdopendir2 \ tst-scandir \ @@ -65,6 +66,18 @@ tests := \ tst-seekdir \ # tests +ifeq ($(run-built-tests),yes) +ifneq ($(PERL),no) +generated += \ + $(objpfx)tst-closedir-leaks-mem.out \ + # generated + +tests-special += \ + $(objpfx)tst-closedir-leaks-mem.out \ + # tests-special +endif # $(PERL) ! no +endif # $(run-built-tests) == yes + CFLAGS-scandir.c += $(uses-callbacks) CFLAGS-scandir64.c += $(uses-callbacks) CFLAGS-scandir-tail.c += $(uses-callbacks) @@ -74,3 +87,10 @@ CFLAGS-dirfd.c += $(config-cflags-wno-ignored-attributes) include ../Rules opendir-tst1-ARGS = --test-dir=${common-objpfx}dirent + +tst-closedir-leaks-ENV += MALLOC_TRACE=$(objpfx)tst-closedir-leaks.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so + +$(objpfx)tst-closedir-leaks-mem.out: $(objpfx)tst-closedir-leaks.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-closedir-leaks.mtrace > $@; \ + $(evaluate-test) diff --git a/dirent/tst-closedir-leaks.c b/dirent/tst-closedir-leaks.c new file mode 100644 index 0000000000..d9de119b63 --- /dev/null +++ b/dirent/tst-closedir-leaks.c @@ -0,0 +1,77 @@ +/* Test for resource leaks in closedir. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +one_test (enum support_readdir_op op, unsigned int read_limit, + bool use_fdopendir) +{ + struct support_descriptors *fds = support_descriptors_list (); + struct support_dirent e = { 0, }; + + DIR *stream; + if (use_fdopendir) + { + int fd = xopen (".", O_RDONLY | O_DIRECTORY, 0); + stream = xfdopendir (fd); + /* The descriptor fd will be closed by closedir below. */ + } + else + stream = xopendir ("."); + for (unsigned int i = 0; i < read_limit; ++i) + if (!support_readdir (stream, op, &e)) + break; + TEST_COMPARE (closedir (stream), 0); + + free (e.d_name); + support_descriptors_check (fds); + support_descriptors_free (fds); +} + +static int +do_test (void) +{ + mtrace (); + + for (int use_fdopendir = 0; use_fdopendir < 2; ++use_fdopendir) + { + /* No reads, operation does not matter. */ + one_test (SUPPORT_READDIR, 0, use_fdopendir); + + for (enum support_readdir_op op = 0; op <= support_readdir_op_last(); + ++op) + { + one_test (op, 1, use_fdopendir); + one_test (op, UINT_MAX, use_fdopendir); /* Unlimited reads. */ + } + } + + return 0; +} + +#include