While looking at another problem, I noticed that in several places GNU
make 3.79's source passes a possibly negative char value to ctype
operations like "isblank". On hosts where characters are signed, this
has undefined behavior; e.g. isblank ('\200') might dump core, though
it more typically just returns a garbage value.
You may recall that I reported a similar set of problems against make
3.78.1 back in September. Most got fixed, but some remain. Perhaps
you relied on "gcc -Wchar-subscripts" to find these problems? That
doesn't work in general, unfortunately.
Here is a patch.
2000-05-17 Paul Eggert <[EMAIL PROTECTED]>
* commands.c (chop_commands): Ensure ctype macro args are nonnegative.
* expand.c (variable_expand_string): Likewise.
* function.c (subst_expand, lookup_function, msdos_openpipe):
Likewise.
* job.c (vms_redirect, start_job_command, new_job, child_execute_job,
construct_command_argv_internal, construct_command_argv): Likewise.
* main.c (decode_env_switches, quote_for_env): Likewise.
* misc.c (collapse_continuations, end_of_token, end_of_token_w32,
next_token): Likewise.
* read.c (read_makefile, do_define, conditional_line,
find_char_unquote,get_next_mword): Likewise.
* variable.c (try_variable_definition): Likewise.
* vpath.c (construct_vpath_list): Likewise.
* w32/pathstuff.c (convert_vpath_to_windows32): Likewise.
===================================================================
RCS file: commands.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- commands.c 2000/02/05 07:37:40 3.79
+++ commands.c 2000/05/18 00:28:13 3.79.0.1
@@ -300,7 +300,7 @@ chop_commands (cmds)
int flags = 0;
for (p = lines[idx];
- isblank (*p) || *p == '-' || *p == '@' || *p == '+';
+ isblank ((unsigned char)*p) || *p == '-' || *p == '@' || *p == '+';
++p)
switch (*p)
{
===================================================================
RCS file: expand.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- expand.c 2000/02/24 18:57:23 3.79
+++ expand.c 2000/05/18 00:28:13 3.79.0.1
@@ -367,7 +367,7 @@ variable_expand_string (line, string, le
break;
default:
- if (isblank (p[-1]))
+ if (isblank ((unsigned char)p[-1]))
break;
/* A $ followed by a random char is a variable reference:
===================================================================
RCS file: function.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- function.c 2000/04/04 19:22:03 3.79
+++ function.c 2000/05/18 00:28:13 3.79.0.1
@@ -92,10 +92,10 @@ subst_expand (o, text, subst, replace, s
/* If we're substituting only by fully matched words,
or only at the ends of words, check that this case qualifies. */
if ((by_word
- && ((p > t && !isblank (p[-1]))
- || (p[slen] != '\0' && !isblank (p[slen]))))
+ && ((p > t && !isblank ((unsigned char)p[-1]))
+ || (p[slen] != '\0' && !isblank ((unsigned char)p[slen]))))
|| (suffix_only
- && (p[slen] != '\0' && !isblank (p[slen]))))
+ && (p[slen] != '\0' && !isblank ((unsigned char)p[slen]))))
/* Struck out. Output the rest of the string that is
no longer to be replaced. */
o = variable_buffer_output (o, subst, slen);
@@ -235,7 +235,7 @@ lookup_function (table, s)
for (; table->name != NULL; ++table)
if (table->len <= len
- && (isblank (s[table->len]) || s[table->len] == '\0')
+ && (isblank ((unsigned char)s[table->len]) || s[table->len] == '\0')
&& strneq (s, table->name, table->len))
return table;
@@ -1274,7 +1274,7 @@ msdos_openpipe (int* pipedes, int *pidp,
extern int dos_command_running, dos_status;
/* Make sure not to bother processing an empty line. */
- while (isblank (*text))
+ while (isblank ((unsigned char)*text))
++text;
if (*text == '\0')
return 0;
===================================================================
RCS file: job.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- job.c 2000/02/24 20:26:25 3.79
+++ job.c 2000/05/18 00:28:13 3.79.0.1
@@ -295,10 +295,10 @@ vms_redirect (desc, fname, ibuf)
extern char *vmsify ();
ibuf++;
- while (isspace (*ibuf))
+ while (isspace ((unsigned char)*ibuf))
ibuf++;
fptr = ibuf;
- while (*ibuf && !isspace (*ibuf))
+ while (*ibuf && !isspace ((unsigned char)*ibuf))
ibuf++;
*ibuf = 0;
if (strcmp (fptr, "/dev/null") != 0)
@@ -890,7 +890,7 @@ start_job_command (child)
flags |= COMMANDS_RECURSE;
else if (*p == '-')
child->noerror = 1;
- else if (!isblank (*p))
+ else if (!isblank ((unsigned char)*p))
break;
++p;
}
@@ -1411,7 +1411,8 @@ new_job (file)
/* Discard any preceding whitespace that has
already been written to the output. */
- while (out > ref && isblank (out[-1]))
+ while (out > ref
+ && isblank ((unsigned char)out[-1]))
--out;
/* Replace it all with a single space. */
@@ -1806,7 +1807,7 @@ child_execute_job (argv, child)
DB (DB_JOBS, ("child_execute_job (%s)\n", argv));
- while (isspace (*argv))
+ while (isspace ((unsigned char)*argv))
argv++;
if (*argv == 0)
@@ -1831,9 +1832,9 @@ child_execute_job (argv, child)
p++;
if (*p == '\n')
p++;
- if (isspace (*p))
+ if (isspace ((unsigned char)*p))
{
- do { p++; } while (isspace (*p));
+ do { p++; } while (isspace ((unsigned char)*p));
p--;
}
*q = *p;
@@ -1993,11 +1994,11 @@ child_execute_job (argv, child)
case '\n':
/* At a newline, skip any whitespace around a leading $
from the command and issue exactly one $ into the DCL. */
- while (isspace (*p))
+ while (isspace ((unsigned char)*p))
p++;
if (*p == '$')
p++;
- while (isspace (*p))
+ while (isspace ((unsigned char)*p))
p++;
fwrite (p, 1, q - p, outfile);
fputc ('$', outfile);
@@ -2444,7 +2445,7 @@ construct_command_argv_internal (line, r
*restp = NULL;
/* Make sure not to bother processing an empty line. */
- while (isblank (*line))
+ while (isblank ((unsigned char)*line))
++line;
if (*line == '\0')
return 0;
@@ -2962,12 +2963,12 @@ construct_command_argv (line, restp, fil
for (;;)
{
while ((*cptr != 0)
- && (isspace (*cptr)))
+ && (isspace ((unsigned char)*cptr)))
cptr++;
if (*cptr == 0)
break;
while ((*cptr != 0)
- && (!isspace(*cptr)))
+ && (!isspace((unsigned char)*cptr)))
cptr++;
argc++;
}
@@ -2981,14 +2982,14 @@ construct_command_argv (line, restp, fil
for (;;)
{
while ((*cptr != 0)
- && (isspace (*cptr)))
+ && (isspace ((unsigned char)*cptr)))
cptr++;
if (*cptr == 0)
break;
DB (DB_JOBS, ("argv[%d] = [%s]\n", argc, cptr));
argv[argc++] = cptr;
while ((*cptr != 0)
- && (!isspace(*cptr)))
+ && (!isspace((unsigned char)*cptr)))
cptr++;
if (*cptr != 0)
*cptr++ = 0;
===================================================================
RCS file: main.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- main.c 2000/02/24 21:00:20 3.79
+++ main.c 2000/05/18 00:28:13 3.79.0.1
@@ -2325,14 +2325,14 @@ decode_env_switches (envar, len)
{
if (*value == '\\' && value[1] != '\0')
++value; /* Skip the backslash. */
- else if (isblank (*value))
+ else if (isblank ((unsigned char)*value))
{
/* End of the word. */
*p++ = '\0';
argv[++argc] = p;
do
++value;
- while (isblank (*value));
+ while (isblank ((unsigned char)*value));
continue;
}
*p++ = *value++;
@@ -2365,7 +2365,7 @@ quote_for_env (out, in)
{
if (*in == '$')
*out++ = '$';
- else if (isblank (*in) || *in == '\\')
+ else if (isblank ((unsigned char)*in) || *in == '\\')
*out++ = '\\';
*out++ = *in++;
}
===================================================================
RCS file: misc.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- misc.c 1999/11/22 06:15:51 3.79
+++ misc.c 2000/05/18 00:28:13 3.79.0.1
@@ -120,7 +120,7 @@ collapse_continuations (line)
if (backslash)
{
in = next_token (in);
- while (out > line && isblank (out[-1]))
+ while (out > line && isblank ((unsigned char)out[-1]))
--out;
*out++ = ' ';
}
@@ -478,7 +478,7 @@ char *
end_of_token (s)
char *s;
{
- while (*s != '\0' && !isblank (*s))
+ while (*s != '\0' && !isblank ((unsigned char)*s))
++s;
return s;
}
@@ -495,7 +495,8 @@ end_of_token_w32 (s, stopchar)
register char *p = s;
register int backslash = 0;
- while (*p != '\0' && *p != stopchar && (backslash || !isblank (*p)))
+ while (*p != '\0' && *p != stopchar
+ && (backslash || !isblank ((unsigned char)*p)))
{
if (*p++ == '\\')
{
@@ -522,7 +523,7 @@ next_token (s)
{
register char *p = s;
- while (isblank (*p))
+ while (isblank ((unsigned char)*p))
++p;
return p;
}
===================================================================
RCS file: read.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- read.c 2000/04/04 23:33:15 3.79
+++ read.c 2000/05/18 00:28:13 3.79.0.1
@@ -550,7 +550,7 @@ read_makefile (filename, flags)
removed), so it could be a complex variable/function
reference that might contain blanks. */
p = strchr (p2, '\0');
- while (isblank (p[-1]))
+ while (isblank ((unsigned char)p[-1]))
--p;
do_define (p2, p - p2, o_file, infile, &fileinfo);
}
@@ -562,7 +562,8 @@ read_makefile (filename, flags)
p2 = next_token (p + 8);
if (*p2 == '\0')
error (&fileinfo, _("empty `override' directive"));
- if (strneq (p2, "define", 6) && (isblank (p2[6]) || p2[6] == '\0'))
+ if (strneq (p2, "define", 6)
+ && (isblank ((unsigned char)p2[6]) || p2[6] == '\0'))
{
if (ignoring)
in_ignored_define = 1;
@@ -577,7 +578,7 @@ read_makefile (filename, flags)
removed), so it could be a complex variable/function
reference that might contain blanks. */
p = strchr (p2, '\0');
- while (isblank (p[-1]))
+ while (isblank ((unsigned char)p[-1]))
--p;
do_define (p2, p - p2, o_override, infile, &fileinfo);
}
@@ -726,7 +727,7 @@ read_makefile (filename, flags)
else if (lb.buffer[0] == '\t')
{
p = collapsed; /* Ignore comments. */
- while (isblank (*p))
+ while (isblank ((unsigned char)*p))
++p;
if (*p == '\0')
/* The line is completely blank; that is harmless. */
@@ -1108,7 +1109,7 @@ do_define (name, namelen, origin, infile
p = next_token (lb.buffer);
len = strlen (p);
- if ((len == 5 || (len > 5 && isblank (p[5])))
+ if ((len == 5 || (len > 5 && isblank ((unsigned char)p[5])))
&& strneq (p, "endef", 5))
{
p += 5;
@@ -1300,7 +1301,7 @@ conditional_line (line, flocp)
{
/* Strip blanks after the first string. */
char *p = line++;
- while (isblank (p[-1]))
+ while (isblank ((unsigned char)p[-1]))
--p;
*p = '\0';
}
@@ -1824,7 +1825,7 @@ find_char_unquote (string, stopchars, bl
while (1)
{
while (*p != '\0' && strchr (stopchars, *p) == 0
- && (!blank || !isblank (*p)))
+ && (!blank || !isblank ((unsigned char)*p)))
++p;
if (*p == '\0')
break;
@@ -2257,7 +2258,7 @@ get_next_mword (buffer, delim, startp, l
char c;
/* Skip any leading whitespace. */
- while (isblank(*p))
+ while (isblank ((unsigned char)*p))
++p;
beg = p;
===================================================================
RCS file: variable.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- variable.c 2000/02/24 18:57:25 3.79
+++ variable.c 2000/05/18 00:28:13 3.79.0.1
@@ -859,7 +859,7 @@ try_variable_definition (flocp, line, or
}
beg = next_token (line);
- while (end > beg && isblank (end[-1]))
+ while (end > beg && isblank ((unsigned char)end[-1]))
--end;
p = next_token (p);
===================================================================
RCS file: vpath.c,v
retrieving revision 3.79
retrieving revision 3.79.0.1
diff -pu -r3.79 -r3.79.0.1
--- vpath.c 1999/10/15 07:01:11 3.79
+++ vpath.c 2000/05/18 00:28:13 3.79.0.1
@@ -222,7 +222,7 @@ construct_vpath_list (pattern, dirpath)
maxelem = 2;
p = dirpath;
while (*p != '\0')
- if (*p++ == PATH_SEPARATOR_CHAR || isblank (*p))
+ if (*p++ == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p))
++maxelem;
vpath = (char **) xmalloc (maxelem * sizeof (char *));
@@ -230,7 +230,7 @@ construct_vpath_list (pattern, dirpath)
/* Skip over any initial separators and blanks. */
p = dirpath;
- while (*p == PATH_SEPARATOR_CHAR || isblank (*p))
+ while (*p == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p))
++p;
elem = 0;
@@ -241,7 +241,8 @@ construct_vpath_list (pattern, dirpath)
/* Find the end of this entry. */
v = p;
- while (*p != '\0' && *p != PATH_SEPARATOR_CHAR && !isblank (*p))
+ while (*p != '\0' && *p != PATH_SEPARATOR_CHAR
+ && !isblank ((unsigned char)*p))
++p;
len = p - v;
@@ -274,7 +275,7 @@ construct_vpath_list (pattern, dirpath)
}
/* Skip over separators and blanks between entries. */
- while (*p == PATH_SEPARATOR_CHAR || isblank (*p))
+ while (*p == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p))
++p;
}
===================================================================
RCS file: w32/pathstuff.c,v
retrieving revision 3.78.1.0
retrieving revision 3.78.1.1
diff -pu -r3.78.1.0 -r3.78.1.1
--- w32/pathstuff.c 1998/07/31 20:39:54 3.78.1.0
+++ w32/pathstuff.c 1999/09/29 18:34:12 3.78.1.1
@@ -16,7 +16,7 @@ convert_vpath_to_windows32(char *Path, c
* contain blanks get trounced here. Use 8.3 format as a workaround.
*/
for (etok = Path; etok && *etok; etok++)
- if (isblank(*etok))
+ if (isblank ((unsigned char) *etok))
*etok = to_delim;
return (convert_Path_to_windows32(Path, to_delim));
@@ -42,7 +42,7 @@ convert_Path_to_windows32(char *Path, ch
etok[0] = to_delim;
p = ++etok;
continue; /* ignore empty bucket */
- } else if (!isalpha(*p)) {
+ } else if (!isalpha ((unsigned char) *p)) {
/* found one to count, handle things like '.' */
*etok = to_delim;
p = ++etok;