From 723ba242a8e1468c1d5f33547de0160fc88299c2 Mon Sep 17 00:00:00 2001 From: hja Date: Mon, 2 Nov 2026 20:24:34 +0000 Subject: [PATCH 1/4] Free file metadata discarded by successful gathers --- .gitignore | 1 + Makefile.am | 8 ++-- lib/dialects/sun/dnode.c | 3 +- lib/lsof.c | 3 ++ tests/LTfilemeta.c | 90 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 tests/LTfilemeta.c diff --git a/.gitignore b/.gitignore index 4a71c548..e2f26f5c 100644 --- a/.gitignore +++ b/.gitignore @@ -113,6 +113,7 @@ lib/dialects/netbsd/include # LTbasic LTbasic2 +LTfilemeta LTbigf LTdnlc LTlock diff --git a/Makefile.am b/Makefile.am index c7048283..5bd2606f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -210,12 +210,14 @@ tests_LTszoff_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include tests_LTunix_SOURCES = tests/LTunix.c tests/LTlib.c tests_LTunix_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include -# LTbasic2 links against liblsof, only build when liblsof is enabled +# Library tests, only build when liblsof is enabled if INSTALL_LIBLSOF -TESTS += tests/LTbasic2 -check_PROGRAMS += tests/LTbasic2 +TESTS += tests/LTbasic2 tests/LTfilemeta +check_PROGRAMS += tests/LTbasic2 tests/LTfilemeta tests_LTbasic2_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include tests_LTbasic2_LDADD = liblsof.la +tests_LTfilemeta_CPPFLAGS = $(liblsof_la_CPPFLAGS) +tests_LTfilemeta_LDADD = liblsof.la endif # Documentation diff --git a/lib/dialects/sun/dnode.c b/lib/dialects/sun/dnode.c index b1d50e94..db33d1dc 100644 --- a/lib/dialects/sun/dnode.c +++ b/lib/dialects/sun/dnode.c @@ -3431,7 +3431,8 @@ void process_node(struct lsof_context *ctx, /* context */ * Set the file system device to the file system type and clear * the doubtful device numbers. */ - Lf->fsdev = Fsinfo[fx]; + /* Like other fsdev values, this must be owned by the file. */ + Lf->fsdev = mkstrcpy(Fsinfo[fx], (MALLOC_S *)NULL); devs = 0; rdevs = 0; } diff --git a/lib/lsof.c b/lib/lsof.c index e74652d3..94308d0e 100644 --- a/lib/lsof.c +++ b/lib/lsof.c @@ -431,8 +431,11 @@ enum lsof_error lsof_gather(struct lsof_context *ctx, for (lf = lp->file; lf; lf = lf_next) { /* free lf */ lf_next = lf->next; + CLEAN(lf->nm); /* selected names were transferred to the result */ CLEAN(lf->nma); CLEAN(lf->dev_ch); + CLEAN(lf->fsdir); + CLEAN(lf->fsdev); #if defined(CLRLFILEADD) CLRLFILEADD(lf) #endif /* defined(CLRLFILEADD) */ diff --git a/tests/LTfilemeta.c b/tests/LTfilemeta.c new file mode 100644 index 00000000..45622907 --- /dev/null +++ b/tests/LTfilemeta.c @@ -0,0 +1,90 @@ +/* LTfilemeta.c -- gather selected and filtered file metadata under a leak checker. + */ + +#ifdef AUTOTOOLS +# include "config.h" +#endif +#include "common.h" +#include "lsof.h" +#include + +int main(int argc, char *argv[]) { + struct lsof_context *ctx = NULL; + struct lsof_result *result = NULL; + struct lsof_file *file; + const char *tmp = getenv("TMPDIR"); + char path[MAXPATHLEN], resolved[MAXPATHLEN]; + int fd = -1, filtered_fd = -1, round, found; + size_t pi, fi; + int status = 1; + + (void)argc; + (void)argv; + + if (snprintf(path, sizeof(path), "%s/lsof-filemeta-XXXXXX", + tmp ? tmp : "/tmp") >= sizeof(path)) + return 1; + fd = mkstemp(path); + if (fd < 0) + return 1; + filtered_fd = dup(fd); + if (filtered_fd < 0 || !realpath(path, resolved)) + goto cleanup; + + ctx = lsof_new(); + if (!ctx || lsof_select_pid(ctx, getpid(), 0) != LSOF_SUCCESS || + lsof_logic_and(ctx) != LSOF_SUCCESS || + lsof_avoid_forking(ctx, 1) != LSOF_SUCCESS) + goto cleanup; + + /* No public FD selector exists yet. Select only fd within this process; + * other records are gathered but their names are not transferred. + */ + ctx->fd_list = calloc(1, sizeof(*ctx->fd_list)); + if (!ctx->fd_list) + goto cleanup; + ctx->fd_list->fd_type = LSOF_FD_NUMERIC; + ctx->fd_list->lo = ctx->fd_list->hi = fd; + ctx->fd_list_ty = 0; + ctx->sel_flags |= SELFD; + + for (round = 0; round < 3; round++) { + if (lsof_gather(ctx, &result) != LSOF_SUCCESS) + goto cleanup; + /* Result names must remain owned by the result, not the context. */ + if (round == 2) { + lsof_destroy(ctx); + ctx = NULL; + } + found = 0; + for (pi = 0; pi < result->num_processes; pi++) { + for (fi = 0; fi < result->processes[pi].num_files; fi++) { + file = &result->processes[pi].files[fi]; + if (file->fd_type == LSOF_FD_NUMERIC && + file->fd_num == filtered_fd) { + fprintf(stderr, "filtered FD returned by gather\n"); + goto cleanup; + } + if (file->fd_type == LSOF_FD_NUMERIC && file->fd_num == fd && + file->name && !strcmp(file->name, resolved)) + found = 1; + } + } + if (!found) { + fprintf(stderr, "selected file name missing or invalid\n"); + goto cleanup; + } + lsof_free_result(result); + result = NULL; + } + status = 0; +cleanup: + lsof_free_result(result); + lsof_destroy(ctx); + if (filtered_fd >= 0) + close(filtered_fd); + if (fd >= 0) + close(fd); + unlink(path); + return status; +} From fec84e965e287435e30cd93db7642028ad95a2c8 Mon Sep 17 00:00:00 2001 From: hja Date: Mon, 2 Nov 2026 20:46:33 +0000 Subject: [PATCH 2/4] ci: retrigger checks for PR #382 From 250656476c49ab92952129852aeebd3e0b0652c3 Mon Sep 17 00:00:00 2001 From: hja Date: Mon, 2 Nov 2026 21:11:03 +0000 Subject: [PATCH 3/4] Accept filesystem details in gathered test file names --- tests/LTfilemeta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/LTfilemeta.c b/tests/LTfilemeta.c index 45622907..b10eede4 100644 --- a/tests/LTfilemeta.c +++ b/tests/LTfilemeta.c @@ -65,8 +65,9 @@ int main(int argc, char *argv[]) { fprintf(stderr, "filtered FD returned by gather\n"); goto cleanup; } + /* NAME may include filesystem details after the pathname. */ if (file->fd_type == LSOF_FD_NUMERIC && file->fd_num == fd && - file->name && !strcmp(file->name, resolved)) + file->name && strstr(file->name, resolved)) found = 1; } } From a9b629a954caf688ef91b0f61d18f0adab506035 Mon Sep 17 00:00:00 2001 From: hja Date: Tue, 3 Nov 2026 02:28:31 +0000 Subject: [PATCH 4/4] Remove file metadata test per review --- .gitignore | 1 - Makefile.am | 8 ++-- tests/LTfilemeta.c | 91 ---------------------------------------------- 3 files changed, 3 insertions(+), 97 deletions(-) delete mode 100644 tests/LTfilemeta.c diff --git a/.gitignore b/.gitignore index e2f26f5c..4a71c548 100644 --- a/.gitignore +++ b/.gitignore @@ -113,7 +113,6 @@ lib/dialects/netbsd/include # LTbasic LTbasic2 -LTfilemeta LTbigf LTdnlc LTlock diff --git a/Makefile.am b/Makefile.am index 5bd2606f..c7048283 100644 --- a/Makefile.am +++ b/Makefile.am @@ -210,14 +210,12 @@ tests_LTszoff_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include tests_LTunix_SOURCES = tests/LTunix.c tests/LTlib.c tests_LTunix_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include -# Library tests, only build when liblsof is enabled +# LTbasic2 links against liblsof, only build when liblsof is enabled if INSTALL_LIBLSOF -TESTS += tests/LTbasic2 tests/LTfilemeta -check_PROGRAMS += tests/LTbasic2 tests/LTfilemeta +TESTS += tests/LTbasic2 +check_PROGRAMS += tests/LTbasic2 tests_LTbasic2_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include tests_LTbasic2_LDADD = liblsof.la -tests_LTfilemeta_CPPFLAGS = $(liblsof_la_CPPFLAGS) -tests_LTfilemeta_LDADD = liblsof.la endif # Documentation diff --git a/tests/LTfilemeta.c b/tests/LTfilemeta.c deleted file mode 100644 index b10eede4..00000000 --- a/tests/LTfilemeta.c +++ /dev/null @@ -1,91 +0,0 @@ -/* LTfilemeta.c -- gather selected and filtered file metadata under a leak checker. - */ - -#ifdef AUTOTOOLS -# include "config.h" -#endif -#include "common.h" -#include "lsof.h" -#include - -int main(int argc, char *argv[]) { - struct lsof_context *ctx = NULL; - struct lsof_result *result = NULL; - struct lsof_file *file; - const char *tmp = getenv("TMPDIR"); - char path[MAXPATHLEN], resolved[MAXPATHLEN]; - int fd = -1, filtered_fd = -1, round, found; - size_t pi, fi; - int status = 1; - - (void)argc; - (void)argv; - - if (snprintf(path, sizeof(path), "%s/lsof-filemeta-XXXXXX", - tmp ? tmp : "/tmp") >= sizeof(path)) - return 1; - fd = mkstemp(path); - if (fd < 0) - return 1; - filtered_fd = dup(fd); - if (filtered_fd < 0 || !realpath(path, resolved)) - goto cleanup; - - ctx = lsof_new(); - if (!ctx || lsof_select_pid(ctx, getpid(), 0) != LSOF_SUCCESS || - lsof_logic_and(ctx) != LSOF_SUCCESS || - lsof_avoid_forking(ctx, 1) != LSOF_SUCCESS) - goto cleanup; - - /* No public FD selector exists yet. Select only fd within this process; - * other records are gathered but their names are not transferred. - */ - ctx->fd_list = calloc(1, sizeof(*ctx->fd_list)); - if (!ctx->fd_list) - goto cleanup; - ctx->fd_list->fd_type = LSOF_FD_NUMERIC; - ctx->fd_list->lo = ctx->fd_list->hi = fd; - ctx->fd_list_ty = 0; - ctx->sel_flags |= SELFD; - - for (round = 0; round < 3; round++) { - if (lsof_gather(ctx, &result) != LSOF_SUCCESS) - goto cleanup; - /* Result names must remain owned by the result, not the context. */ - if (round == 2) { - lsof_destroy(ctx); - ctx = NULL; - } - found = 0; - for (pi = 0; pi < result->num_processes; pi++) { - for (fi = 0; fi < result->processes[pi].num_files; fi++) { - file = &result->processes[pi].files[fi]; - if (file->fd_type == LSOF_FD_NUMERIC && - file->fd_num == filtered_fd) { - fprintf(stderr, "filtered FD returned by gather\n"); - goto cleanup; - } - /* NAME may include filesystem details after the pathname. */ - if (file->fd_type == LSOF_FD_NUMERIC && file->fd_num == fd && - file->name && strstr(file->name, resolved)) - found = 1; - } - } - if (!found) { - fprintf(stderr, "selected file name missing or invalid\n"); - goto cleanup; - } - lsof_free_result(result); - result = NULL; - } - status = 0; -cleanup: - lsof_free_result(result); - lsof_destroy(ctx); - if (filtered_fd >= 0) - close(filtered_fd); - if (fd >= 0) - close(fd); - unlink(path); - return status; -}