Module Name:    src
Committed By:   rillig
Date:           Sat Oct 31 23:39:01 UTC 2020

Modified Files:
        src/usr.bin/make: parse.c

Log Message:
make(1): fix out-of-bounds pointer in ParseTrackInput


To generate a diff of this commit:
cvs rdiff -u -r1.417 -r1.418 src/usr.bin/make/parse.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/parse.c
diff -u src/usr.bin/make/parse.c:1.417 src/usr.bin/make/parse.c:1.418
--- src/usr.bin/make/parse.c:1.417	Sat Oct 31 23:10:06 2020
+++ src/usr.bin/make/parse.c	Sat Oct 31 23:39:01 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: parse.c,v 1.417 2020/10/31 23:10:06 rillig Exp $	*/
+/*	$NetBSD: parse.c,v 1.418 2020/10/31 23:39:01 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -117,7 +117,7 @@
 #include "pathnames.h"
 
 /*	"@(#)parse.c	8.3 (Berkeley) 3/19/94"	*/
-MAKE_RCSID("$NetBSD: parse.c,v 1.417 2020/10/31 23:10:06 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.418 2020/10/31 23:39:01 rillig Exp $");
 
 /* types and constants */
 
@@ -2351,32 +2351,50 @@ ParseSetParseFile(const char *filename)
     }
 }
 
+static Boolean
+StrContainsWord(const char *str, const char *word)
+{
+    const char *val = str;
+    size_t valLen = strlen(val);
+    size_t wordLen = strlen(word);
+    const char *end;
+
+    if (valLen < wordLen)
+	return FALSE;		/* str is too short to contain word */
+
+    end = val + valLen - wordLen;
+    for (; val != NULL; val = strchr(val, ' ')) {
+	if (*val == ' ')
+	    val++;
+	if (val > end)
+	    return FALSE;	/* cannot contain word */
+
+	if (memcmp(val, word, wordLen) == 0 &&
+	    (val[wordLen] == '\0' || val[wordLen] == ' '))
+	    return TRUE;
+    }
+    return FALSE;
+}
+
+/* XXX: Searching through a set of words with this linear search is
+ * inefficient for variables that contain thousands of words. */
+static Boolean
+VarContainsWord(const char *varname, const char *word)
+{
+    void *val_freeIt;
+    const char *val = Var_Value(varname, VAR_GLOBAL, &val_freeIt);
+    Boolean found = val != NULL && StrContainsWord(val, word);
+    bmake_free(val_freeIt);
+    return found;
+}
+
 /* Track the makefiles we read - so makefiles can set dependencies on them.
  * Avoid adding anything more than once. */
 static void
 ParseTrackInput(const char *name)
 {
-    void *old_freeIt = NULL;
-
-    const char *old = Var_Value(MAKE_MAKEFILES, VAR_GLOBAL, &old_freeIt);
-    if (old != NULL) {
-	size_t name_len = strlen(name);
-	/* XXX: undefined behavior if name_len > strlen(old) */
-	const char *ep = old + strlen(old) - name_len;
-	/* does it contain name? */
-	for (; old != NULL; old = strchr(old, ' ')) {
-	    if (*old == ' ')
-		old++;
-	    if (old > ep)
-		break;		/* cannot contain name */
-	    if (memcmp(old, name, name_len) == 0 &&
-		(old[name_len] == '\0' || old[name_len] == ' '))
-		goto cleanup;
-	}
-    }
-    Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL);
-cleanup:
-    bmake_free(old_freeIt);
+    if (!VarContainsWord(MAKE_MAKEFILES, name))
+	Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL);
 }
 
 

Reply via email to