File: 0005-Fix-large-command-line-on-POSIX-systems.patch

package info (click to toggle)
make-dfsg 4.4.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,948 kB
  • sloc: ansic: 31,304; sh: 5,222; perl: 1,716; makefile: 162; lisp: 26; sed: 16
file content (178 lines) | stat: -rw-r--r-- 5,695 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
From: Mike Crowe <mac@mcrowe.com>
Date: Fri, 6 Nov 2020 15:22:37 +0000
Subject: Fix large command line on POSIX systems

When presented with a very long command line (as is common when linking
a large number of files with absolute paths in a deep subdirectory),
make fails to execute the command as it doesn't split the command line
to fit within the limits.

This is based on a fix for Debian bug 688601[1] by Adam Conrad applied
by Manoj Srivastava originally applied for Debian make-dfsg 4.0-5 in
2014 but dropped in 2018 (it seems under the incorrect assumption that
it had been accepted upstream.)

I've tweaked Adam's original patch so that it compiles successfully with
-Werror on top of current master. This required:

* moving the eval_line declaration to the top of the block, so I moved
  the macros too
* using a const variable when iterating over the shell
* adding a cast to avoid a signed/unsigned mismatch.

As suggested in the Savannah bug report[2], I've added a test case that
fails without the rest of the patch. I'm not sure what the consequences
of running the test on non-POSIX targets would be and whether it needs
marking as an expected failure.

* src/job.c (construct_command_argv_internal): support running commands
longer than MAX_ARG_STRLEN
* tests/scripts/features/long_command_line: add test for such a command
* configure.ac: check for now-required sys/user.h and linux/binfmts.h
headers

[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=688601
[2] https://savannah.gnu.org/bugs/?45763#comment2

Bug: https://savannah.gnu.org/bugs/?45763
Last-Update: 2023-02-13
---
 configure.ac                             |  2 +-
 src/job.c                                | 52 +++++++++++++++++++++++++++++++-
 tests/scripts/features/long_command_line | 30 ++++++++++++++++++
 3 files changed, 82 insertions(+), 2 deletions(-)
 create mode 100644 tests/scripts/features/long_command_line

--- a/configure.ac
+++ b/configure.ac
@@ -68,7 +68,7 @@
 
 AC_CHECK_HEADERS([stdlib.h string.h strings.h locale.h unistd.h limits.h \
                   memory.h sys/param.h sys/resource.h sys/timeb.h sys/time.h \
-                  sys/select.h sys/file.h fcntl.h spawn.h])
+                  sys/select.h sys/file.h fcntl.h spawn.h sys/user.h linux/binfmts.h])
 
 AM_PROG_CC_C_O
 AC_C_CONST
--- a/src/job.c
+++ b/src/job.c
@@ -28,6 +28,14 @@
 #include "dep.h"
 #include "shuffle.h"
 
+#if defined (HAVE_LINUX_BINFMTS_H) && defined (HAVE_SYS_USER_H)
+#include <sys/user.h>
+#include <linux/binfmts.h>
+#endif
+#ifndef PAGE_SIZE
+# define PAGE_SIZE (sysconf(_SC_PAGESIZE))
+#endif
+
 /* Default shell to use.  */
 #ifdef WINDOWS32
 # include <windows.h>
@@ -3274,6 +3282,15 @@
 #ifdef WINDOWS32
     char *command_ptr = NULL; /* used for batch_mode_shell mode */
 #endif
+    char *args_ptr;
+#ifdef MAX_ARG_STRLEN
+    static char eval_line[] = "eval\\ \\\"set\\ x\\;\\ shift\\;\\ ";
+#define ARG_NUMBER_DIGITS 5
+#define EVAL_LEN (sizeof(eval_line)-1 + shell_len + 4                   \
+                  + (7 + ARG_NUMBER_DIGITS) * 2 * line_len / (MAX_ARG_STRLEN - 2))
+#else
+#define EVAL_LEN 0
+#endif
 
 # ifdef __EMX__ /* is this necessary? */
     if (!unixy_shell && shellflags)
@@ -3465,7 +3482,7 @@
       }
 
     new_line = xmalloc ((shell_len*2) + 1 + sflags_len + 1
-                        + (line_len*2) + 1);
+                        + (line_len*2) + 1 + EVAL_LEN);
     ap = new_line;
     /* Copy SHELL, escaping any characters special to the shell.  If
        we don't escape them, construct_command_argv_internal will
@@ -3486,6 +3503,31 @@
 #ifdef WINDOWS32
     command_ptr = ap;
 #endif
+
+#if !defined (WINDOWS32) && defined (MAX_ARG_STRLEN)
+    if (unixy_shell && line_len > MAX_ARG_STRLEN)
+      {
+       const char *q;
+       unsigned j;
+       memcpy (ap, eval_line, sizeof (eval_line) - 1);
+       ap += sizeof (eval_line) - 1;
+       for (j = 1; j <= 2 * line_len / (MAX_ARG_STRLEN - 2); j++)
+         ap += sprintf (ap, "\\$\\{%u\\}", j);
+       *ap++ = '\\';
+       *ap++ = '"';
+       *ap++ = ' ';
+       /* Copy only the first word of SHELL to $0.  */
+       for (q = shell; *q != '\0'; ++q)
+         {
+           if (isspace ((unsigned char)*q))
+             break;
+           *ap++ = *q;
+         }
+       *ap++ = ' ';
+      }
+#endif
+    args_ptr = ap;
+
     for (p = line; *p != '\0'; ++p)
       {
         if (restp != NULL && *p == '\n')
@@ -3532,6 +3574,14 @@
           }
 #endif
         *ap++ = *p;
+#if !defined (WINDOWS32) && defined (MAX_ARG_STRLEN)
+        if (unixy_shell && line_len > MAX_ARG_STRLEN
+            && (ap - args_ptr > (long)(MAX_ARG_STRLEN - 2)))
+         {
+           *ap++ = ' ';
+           args_ptr = ap;
+         }
+#endif
       }
     if (ap == new_line + shell_len + sflags_len + 2)
       {
--- /dev/null
+++ b/tests/scripts/features/long_command_line
@@ -0,0 +1,30 @@
+#                                                                    -*-perl-*-
+$description = "Test long command line.";
+
+$details = "";
+
+# Variable names containing UTF8 characters
+run_make_test(q!
+# 49 characters
+ARGS:=one two three four five six seven eight niner ten
+# 49*4+3 = 199 characters
+ARGS:=$(ARGS) $(ARGS) $(ARGS) $(ARGS)
+# 199*4+3 = 799 characters
+ARGS:=$(ARGS) $(ARGS) $(ARGS) $(ARGS)
+# 799*4+3 = 3199 characters
+ARGS:=$(ARGS) $(ARGS) $(ARGS) $(ARGS)
+# 3199*4+3 = 12799 characters
+ARGS:=$(ARGS) $(ARGS) $(ARGS) $(ARGS)
+# 12799*4+3 = 51199 characters
+ARGS:=$(ARGS) $(ARGS) $(ARGS) $(ARGS)
+# 51199*4+3 = 204799 characters
+ARGS:=$(ARGS) $(ARGS) $(ARGS) $(ARGS)
+# 24799*2+1 = 409599 characters
+#ARGS:=$(ARGS) $(ARGS)
+
+test:
+	@: $(ARGS)
+!,
+              '', "");
+
+1;