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;