[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.
diff --git a/src/posixos.c b/src/posixos.c
index 163ca6e..27b6979 100644
--- a/src/posixos.c
+++ b/src/posixos.c
@@ -122,10 +122,8 @@
}
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 @@
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 @@
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 @@
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);
diff --git a/tests/scripts/features/jobserver b/tests/scripts/features/jobserver
index 50d51f8..5bdf4a5 100644
--- a/tests/scripts/features/jobserver
+++ b/tests/scripts/features/jobserver
@@ -211,4 +211,15 @@
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;