See attached patch. The supervisor created the shared memory object
with shm_open and unlinked it only on a normal exit, so when it was
stopped by a signal (a testsuite timeout, ^C) the object stayed in
/dev/shm. The fix passes the open descriptor to the images in
GFORTRAN_SHMEM_FD and unlinks the name right after the object is sized,
so the kernel frees it when the last process closes it, however the
program ends.
All of it is in shared_memory_init and shared_memory_cleanup in
shared_memory.c. In the supervisor branch, clearing FD_CLOEXEC keeps
the descriptor across the execve of the images; if that fails the
name is kept and the old shm_open path is used. The image branch takes
the descriptor from the environment. MADV_DONTDUMP is needed because
the kernel dumps an unlinked object like anonymous memory: without it
an image that aborts writes the whole pool into its core file.
shared_memory_cleanup skips shm_unlink when the name is already gone.
The code is under HAVE_SETENV, so other targets are unchanged.
There is no test, since it needs a signal sent to the program. By
hand: a program that never ends, run under "timeout 2", leaves no
/dev/shm/gfor-shm-* behind. A signal sent to the supervisor's pid alone
still leaves the images running, because the supervisor has no signal
handler; that is a separate, older problem, and with this patch the
object goes away once those images are killed.
Regression tested on x86_64.
OK for mainline?
Regards,
Jerry
---
libgfortran: [PR127753] caf_shmem: do not leak the shared memory object
When the supervisor was stopped by a signal, for example by a timeout or
^C, it exited without unlinking the shared memory object, so the object
was left behind in /dev/shm.
The supervisor now passes the descriptor of the object to the images and
removes its name right after creating it, so that the object goes away
with the last process however the program ends. The mapping is excluded
from core dumps, because the kernel dumps an unlinked object like
anonymous memory, which would write out the whole pool.
Assisted-by: Claude Opus 5.5
PR libfortran/127753
libgfortran/ChangeLog:
* caf/shmem/shared_memory.c (ENV_FD): New.
(shared_memory_init): Pass the descriptor to the images through
ENV_FD and unlink the object. Use the inherited descriptor in an
image. Exclude the mapping from core dumps.
(shared_memory_cleanup): Do not unlink an unlinked object.
>From 55981708a07d9232b529ec087dbf213020a2600f Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Mon, 5 Oct 2026 11:06:08 -0700
Subject: [PATCH] libgfortran: [PR127753] caf_shmem: do not leak the shared
memory object
When the supervisor was stopped by a signal, for example by a timeout or
^C, it exited without unlinking the shared memory object, so the object
was left behind in /dev/shm.
The supervisor now passes the descriptor of the object to the images and
removes its name right after creating it, so that the object goes away
with the last process however the program ends. The mapping is excluded
from core dumps, because the kernel dumps an unlinked object like
anonymous memory, which would write out the whole pool.
Assisted-by: Claude Opus 5.5
PR libfortran/127753
libgfortran/ChangeLog:
* caf/shmem/shared_memory.c (ENV_FD): New.
(shared_memory_init): Pass the descriptor to the images through
ENV_FD and unlink the object. Use the inherited descriptor in an
image. Exclude the mapping from core dumps.
(shared_memory_cleanup): Do not unlink an unlinked object.
---
libgfortran/caf/shmem/shared_memory.c | 34 +++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/libgfortran/caf/shmem/shared_memory.c b/libgfortran/caf/shmem/shared_memory.c
index cbe4b0451a6..f111e82da17 100644
--- a/libgfortran/caf/shmem/shared_memory.c
+++ b/libgfortran/caf/shmem/shared_memory.c
@@ -58,6 +58,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
static const char *ENV_PPID = "GFORTRAN_SHMEM_PPID";
static const char *ENV_BASE = "GFORTRAN_SHMEM_BASE";
+#if defined(HAVE_MMAP) && defined(HAVE_SETENV)
+/* The descriptor of the shared memory object the images inherit. */
+static const char *ENV_FD = "GFORTRAN_SHMEM_FD";
+#endif
void
shared_memory_set_env (pid_t pid)
@@ -181,6 +185,17 @@ shared_memory_init (shared_memory_act *mem, size_t size)
perror ("resizing shared memory segment failed.");
exit (1);
}
+#ifdef HAVE_SETENV
+ /* Pass the descriptor to the images and remove the name, so that the
+ object goes away with the last process however the program ends. */
+ if (fcntl (mem->shm_fd, F_SETFD, 0) == 0)
+ {
+ char val[20];
+ snprintf (val, 20, "%d", mem->shm_fd);
+ setenv (ENV_FD, val, 1);
+ shm_unlink (shm_name);
+ }
+#endif
#elif defined(WIN32)
mem->shm_fd
= CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
@@ -216,7 +231,13 @@ shared_memory_init (shared_memory_act *mem, size_t size)
else
{
#ifdef HAVE_MMAP
- mem->shm_fd = shm_open (shm_name, O_RDWR, 0600);
+#ifdef HAVE_SETENV
+ const char *fd_val = getenv (ENV_FD);
+ if (fd_val)
+ mem->shm_fd = atoi (fd_val);
+ else
+#endif
+ mem->shm_fd = shm_open (shm_name, O_RDWR, 0600);
if (mem->shm_fd == -1)
{
perror ("opening shared memory segment failed.");
@@ -246,6 +267,11 @@ shared_memory_init (shared_memory_act *mem, size_t size)
perror ("mmap failed");
exit (1);
}
+#ifdef MADV_DONTDUMP
+ /* Keep the unlinked object, which counts as anonymous shared memory, out
+ of core dumps. */
+ madvise (mem->glbl.base, size, MADV_DONTDUMP);
+#endif
#elif defined(WIN32)
mem->glbl.base
= (LPTSTR) MapViewOfFileEx (mem->shm_fd, FILE_MAP_ALL_ACCESS, 0, 0,
@@ -296,7 +322,11 @@ shared_memory_cleanup (shared_memory_act *mem)
{
perror ("closing shm file handle failed. Trying to continue...");
}
- if (this_image.image_num == -1)
+ if (this_image.image_num == -1
+#ifdef HAVE_SETENV
+ && !getenv (ENV_FD)
+#endif
+ )
{
char shm_name[SHM_NAME_MAX];
--
2.56.0