]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 54549] Don't free used set_lists during merge
authorPaul Smith <psmith@gnu.org>
Sun, 19 May 2019 14:59:06 +0000 (10:59 -0400)
committerPaul Smith <psmith@gnu.org>
Sun, 19 May 2019 19:27:26 +0000 (15:27 -0400)
When merging the variable_set_lists for two targets it could be
that the "from" set list is a subset of the "to" set list: check
for this situation to avoid freeing used memory.

* src/variable.c (merge_variable_set_lists): Walk the "to" list and
if the "from" list is contained in it, nothing to do.
* tests/scripts/features/se_explicit: Add a test.

src/variable.c
tests/scripts/features/se_explicit

index e6822e44bc4d589183f5eac5d5744bc7998f96be..841ff11bcaae3a10d969132db09925f53410cb81 100644 (file)
@@ -782,22 +782,34 @@ merge_variable_set_lists (struct variable_set_list **setlist0,
   struct variable_set_list *last0 = 0;
 
   /* If there's nothing to merge, stop now.  */
-  if (!setlist1)
+  if (!setlist1 || setlist1 == &global_setlist)
     return;
 
-  /* This loop relies on the fact that all setlists terminate with the global
-     setlist (before NULL).  If that's not true, arguably we SHOULD die.  */
   if (to)
-    while (setlist1 != &global_setlist && to != &global_setlist)
-      {
-        struct variable_set_list *from = setlist1;
-        setlist1 = setlist1->next;
+    {
+      /* These loops rely on the fact that all setlists terminate with the
+         global setlist (before NULL).  If not, arguably we SHOULD die.  */
 
-        merge_variable_sets (to->set, from->set);
+      /* Make sure that setlist1 is not already a subset of setlist0.  */
+      while (to != &global_setlist)
+        {
+          if (to == setlist1)
+            return;
+          to = to->next;
+        }
 
-        last0 = to;
-        to = to->next;
-      }
+      to = *setlist0;
+      while (setlist1 != &global_setlist && to != &global_setlist)
+        {
+          struct variable_set_list *from = setlist1;
+          setlist1 = setlist1->next;
+
+          merge_variable_sets (to->set, from->set);
+
+          last0 = to;
+          to = to->next;
+        }
+    }
 
   if (setlist1 != &global_setlist)
     {
index 790017af7c3a91cb67a60acf565256cc28e382ba..fad3da01c5e2e300bc4445a031164417af040edc 100644 (file)
@@ -164,4 +164,30 @@ foo: $$(@\\:%=%.bar); @echo '$^'
 !,
               '', "foo.bar\n");
 
+# SV 54549 : Ensure we don't free used variable_sets
+run_make_test(q!
+foo: -lcat
+
+# Removing second expansion prevents segfault
+.SECONDEXPANSION:
+foo: $$@.o ;
+
+# Having an empty command here prevents segfault unless,
+# the environment is empty. `env -i make foo`
+# MFLAGS=-w or MAKEFLAGS=-w `env MFLAGS=-w make foo`
+# libcat.a target calls an extra command, `@true \n @touch $@`
+# odd.
+%.o: ; @true
+
+# Having an empty command prevents segfault.
+-l%: lib%.a ; @true
+
+# Not creating libcat.a here prevents segfault,
+libcat.a: ; @touch $@
+!,
+              '', q!#MAKEFILE#:16: Recipe was specified for file '-lcat' at #MAKEFILE#:19,
+#MAKEFILE#:16: but '-lcat' is now considered the same file as 'libcat.a'.
+#MAKEFILE#:16: Recipe for 'libcat.a' will be ignored in favor of the one for '-lcat'.!);
+unlink('libcat.a');
+
 1;