[SV 66499] Detect jobserver values that are too large

Set the jobserver pipe to non-blocking before writing tokens; if a
token write fails the user's jobserver value is too large so fail.

Original implementation: Dmitry Goncharov <dgoncharov@users.sf.net>

* src/posixos.c (set_blocking): Split into force_blocking() which
always enables/disables blocking; set_blocking() may call it.
(jobserver_setup): Set the write side of the pipe to non-blocking
before writing tokens.  If it fails with EAGAIN we know the pipe
is full: create a fatal error.
* tests/scripts/features/jobserver: Test a too-large jobserver.
This commit is contained in:
Paul Smith 2024-12-08 16:31:54 -05:00
parent f12a4fddce
commit d523661ce2
2 changed files with 32 additions and 6 deletions

View file

@ -122,10 +122,8 @@ make_job_rfd ()
}
static void
set_blocking (int fd, int blocking)
force_blocking (int fd, int blocking)
{
/* If we're not using pselect() don't change the blocking. */
#ifdef HAVE_PSELECT
int flags;
EINTRLOOP (flags, fcntl (fd, F_GETFL));
if (flags >= 0)
@ -136,6 +134,14 @@ set_blocking (int fd, int blocking)
if (r < 0)
pfatal_with_name ("fcntl(O_NONBLOCK)");
}
}
static void
set_blocking (int fd, int blocking)
{
/* If we're not using pselect() don't change the blocking. */
#ifdef HAVE_PSELECT
force_blocking (fd, blocking);
#else
(void) fd;
(void) blocking;
@ -145,7 +151,7 @@ set_blocking (int fd, int blocking)
unsigned int
jobserver_setup (int slots, const char *style)
{
int r;
int r, k;
/* This function sets up the root jobserver. */
job_root = 1;
@ -211,12 +217,21 @@ jobserver_setup (int slots, const char *style)
if (make_job_rfd () < 0)
pfatal_with_name (_("duping jobs pipe"));
while (slots--)
/* Set the write side of the pipe to non blocking in case the number of
slots specified by the user exceeds pipe capacity. */
force_blocking (job_fds[1], 0);
for (k = 0; k < slots; ++k)
{
EINTRLOOP (r, write (job_fds[1], &token, 1));
if (r != 1)
pfatal_with_name (_("init jobserver pipe"));
{
if (errno != EAGAIN)
pfatal_with_name (_("init jobserver pipe"));
ONN (fatal, NILF, _("requested job count (%d) is larger than system limit (%d)"), slots+1, k);
}
}
force_blocking (job_fds[1], 1);
/* When using pselect() we want the read to be non-blocking. */
set_blocking (job_fds[0], 0);

View file

@ -211,4 +211,15 @@ all:;@echo "$$MAKEFLAGS"
run_make_test(q!all:;@echo hi!, "", "#MAKE#: cannot open jobserver nosuchfile: $ERR_no_such_file\n#MAKE#: $j1err\nhi\n");
}
if ($port_type eq 'UNIX') {
# sv 66499. The specified number of jobs exceeds pipe capacity.
run_make_test(q!
all:; $(info hello, world)
!, '-j688777', '/requested job count \(688777\) is larger than system limit/', 512);
run_make_test(q!
all:; $(info hello, world)
!, '-j688777 --jobserver-style=pipe', '/requested job count \(688777\) is larger than system limit/', 512);
}
1;