* [Bug 220845] New: imprecise 'close_range' description of 'CLOSE_RANGE_UNSHARE'
@ 2025-12-08 4:15 bugzilla-daemon
0 siblings, 0 replies; only message in thread
From: bugzilla-daemon @ 2025-12-08 4:15 UTC (permalink / raw)
To: linux-man
https://bugzilla.kernel.org/show_bug.cgi?id=220845
Bug ID: 220845
Summary: imprecise 'close_range' description of
'CLOSE_RANGE_UNSHARE'
Product: Documentation
Version: unspecified
Hardware: All
OS: Linux
Status: NEW
Severity: enhancement
Priority: P3
Component: man-pages
Assignee: documentation_man-pages@kernel-bugs.osdl.org
Reporter: matthew.fernandez@gmail.com
Regression: No
I’m looking into some more subtle behaviours of `close_range`. The man page
describes the effect of the `CLOSE_RANGE_UNSHARE` flag as:
> Unshare the specified file descriptors from any other processes before
> closing them, avoiding races with other threads sharing the file descriptor
> table.
This sounds as if it unshares _only_ the file descriptors included in the given
range. E.g. `close_range(1, 2, CLOSE_RANGE_UNSHARE)` would unshare FDs 1 and 2
but not 3. This surprised me as I thought it was only possible to share an
entire file descriptor table, not only certain file descriptors within that
table.
I wrote the attached program below to confirm my understanding; `close_range(…,
CLOSE_RANGE_UNSHARE)` appears to unshare the entire file descriptor table, not
just the specified range. Is this correct? If so, do you think the wording
should be adjusted to make this more precise? I’m not sure if my misreading
here is a common misunderstanding.
--
// $ gcc -std=c23 -Wall -Wextra main.c
// $ ./a.out
// a.out: main.c:69: main: Assertion `r1 == 0' failed.
// [2] 7961 IOT instruction (core dumped) ./a.out
// $ gcc -DCLOSE_RANGE -std=c23 -Wall -Wextra main.c
// $ ./a.out
//
#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <linux/close_range.h>
#include <sched.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
static int a;
static int b;
static int child(void *) {
// close both FDs
#ifdef CLOSE_RANGE
const int r1 = close_range(a, a, CLOSE_RANGE_UNSHARE);
#else
const int r1 = close(a);
#endif
assert(r1 == 0);
const int r2 = close(b);
assert(r2 == 0);
return 0;
}
int main(void) {
// create two FDs we’ll share to the child
a = open("/dev/null", O_RDONLY);
assert(a >= 0);
b = open("/dev/null", O_RDONLY);
assert(b >= 0);
assert(b > a);
// create a stack for our upcoming child
enum { STACK_SIZE = 1024 * 1024 };
char *const stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
assert(stack != MAP_FAILED);
#ifdef __hppa__
char *const stack_top = stack;
#else
char *const stack_top = stack + STACK_SIZE;
#endif
// create a child who shares our file descriptor table
const pid_t pid = clone(child, stack_top, CLONE_FILES, NULL);
assert(pid >= 0);
// wait for the child to finish
int status;
const pid_t r = waitpid(pid, &status, __WALL);
assert(r == pid);
assert(WIFEXITED(status) && WEXITSTATUS(status) == 0);
// try closing our shared files
const int r1 = close(a);
assert(r1 == 0);
const int r2 = close(b);
assert(r2 == 0);
(void)munmap(stack, STACK_SIZE);
return 0;
}
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are watching the assignee of the bug.
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-12-08 4:15 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-08 4:15 [Bug 220845] New: imprecise 'close_range' description of 'CLOSE_RANGE_UNSHARE' bugzilla-daemon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).