Fixed Savannah bug #16053.
authorBoris Kolpackov <boris@kolpackov.net>
Fri, 17 Mar 2006 14:24:20 +0000 (14:24 +0000)
committerBoris Kolpackov <boris@kolpackov.net>
Fri, 17 Mar 2006 14:24:20 +0000 (14:24 +0000)
ChangeLog
dep.h
file.c
implicit.c
main.c
misc.c
read.c
remake.c
rule.c
tests/ChangeLog
tests/scripts/features/statipattrules

index abe3b9b93cce07fd219f387f76ffa2a61d9bbdd2..6fc7aef368ceceeddad19d0685e487a30dabff10 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2006-03-17  Boris Kolpackov  <boris@kolpackov.net>
+
+       * dep.h (struct dep): Add the stem field.
+       * misc.c (alloc_dep, free_dep): New functions.
+       (copy_dep_chain): Copy stem.
+       (free_dep_chain): Use free_dep.
+       * read.c (record_files): Store stem in the dependency line.
+       * file.c (expand_deps): Use stem stored in the dependency line. Use
+       free_dep_chain instead of free_ns_chain.
+       * implicit.c (pattern_search): Use alloc_dep and free_dep.
+       * read.c (read_all_makefiles, eval_makefile, eval): Ditto.
+       * main.c (main, handle_non_switch_argument): Ditto.
+       * remake.c (check_dep): Ditto.
+       * rule.c (convert_suffix_rule, freerule): Ditto.
+
 2006-03-14  Paul D. Smith  <psmith@gnu.org>
 
        * expand.c (variable_append): Instead of appending everything then
 
 2006-02-08  Boris Kolpackov  <boris@kolpackov.net>
 
-       * job.h (struct child): Add dontcare bitfield.
+       * job.h (struct child): Add the dontcare bitfield.
        * job.c (new_job): Cache dontcare flag.
        * job.c (reap_children): Use cached dontcare flag instead of the
        one in struct file. Fixes Savannah bug #15641.
diff --git a/dep.h b/dep.h
index aafadb25d3b4c01f3f190fe0d71bc02d2f41b5b1..f0923cc2ed63f1c23a4a628e4271a242131d328f 100644 (file)
--- a/dep.h
+++ b/dep.h
@@ -28,7 +28,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
 
 /* Structure representing one dependency of a file.
    Each struct file's `deps' points to a chain of these,
-   chained through the `next'.
+   chained through the `next'. `stem' is the stem for this
+   dep line of static pattern rule or NULL.
 
    Note that the first two words of this match a struct nameseq.  */
 
@@ -36,6 +37,7 @@ struct dep
   {
     struct dep *next;
     char *name;
+    char *stem;
     struct file *file;
     unsigned int changed : 8;
     unsigned int ignore_mtime : 1;
@@ -72,6 +74,8 @@ extern struct nameseq *ar_glob PARAMS ((char *arname, char *member_pattern, unsi
 extern char *dep_name ();
 #endif
 
+extern struct dep *alloc_dep PARAMS ((void));
+extern void free_dep PARAMS ((struct dep *d));
 extern struct dep *copy_dep_chain PARAMS ((const struct dep *d));
 extern void free_dep_chain PARAMS ((struct dep *d));
 extern void free_ns_chain PARAMS ((struct nameseq *n));
diff --git a/file.c b/file.c
index a0e82228b3adabe80ce16f0e8dd82229bc38a042..90dd123058460d2f0c926af3df9a5e27450c30c5 100644 (file)
--- a/file.c
+++ b/file.c
@@ -460,6 +460,7 @@ expand_deps (struct file *f)
 {
   struct dep *d;
   struct dep *old = f->deps;
+  char *file_stem = f->stem;
   unsigned int last_dep_has_cmds = f->updating;
   int initialized = 0;
 
@@ -491,20 +492,29 @@ expand_deps (struct file *f)
 
               free (d->name);
               d->name = savestring (buffer, o - buffer);
-              d->staticpattern = 0;
+              d->staticpattern = 0; /* Clear staticpattern so that we don't
+                                       re-expand %s below. */
             }
 
           /* We are going to do second expansion so initialize file variables
-             for the file. */
+             for the file. Since the stem for static pattern rules comes from
+             individual dep lines, we will temporarily set f->stem to d->stem.
+          */
           if (!initialized)
             {
               initialize_file_variables (f, 0);
               initialized = 1;
             }
 
+          if (d->stem != 0)
+            f->stem = d->stem;
+
           set_file_variables (f);
 
           p = variable_expand_for_file (d->name, f);
+
+          if (d->stem != 0)
+            f->stem = file_stem;
         }
 
       /* Parse the prerequisites.  */
@@ -527,12 +537,12 @@ expand_deps (struct file *f)
                   /* We have to handle empty stems specially, because that
                      would be equivalent to $(patsubst %,dp->name,) which
                      will always be empty.  */
-                  if (f->stem[0] == '\0')
+                  if (d->stem[0] == '\0')
                     /* This needs memmove() in ISO C.  */
                     bcopy (percent+1, percent, strlen (percent));
                   else
                     {
-                      char *o = patsubst_expand (buffer, f->stem, pattern,
+                      char *o = patsubst_expand (buffer, d->stem, pattern,
                                                  dp->name, pattern+1,
                                                  percent+1);
                       if (o == buffer)
@@ -552,7 +562,9 @@ expand_deps (struct file *f)
                         dp = new = new->next;
                       else
                         dp = dl->next = dp->next;
-                      free ((char *)df);
+                      /* @@ Are we leaking df->name here?  */
+                      df->name = 0;
+                      free_dep (df);
                       continue;
                     }
                 }
@@ -604,7 +616,7 @@ expand_deps (struct file *f)
         }
     }
 
-  free_ns_chain ((struct nameseq *) old);
+  free_dep_chain (old);
 }
 
 /* For each dependency of each file, make the `struct dep' point
index 8085ea10f12f1f182724cb5b8f65d4f8df0adfae..a5d37008f72aa5faea4da0185e42979a71cbc204 100644 (file)
@@ -802,8 +802,7 @@ pattern_search (struct file *file, int archive,
       while (dep != 0)
         {
           struct dep *next = dep->next;
-          free (dep->name);
-          free ((char *)dep);
+          free_dep (dep);
           dep = next;
         }
       file->deps = 0;
@@ -862,15 +861,12 @@ pattern_search (struct file *file, int archive,
            }
        }
 
-      dep = (struct dep *) xmalloc (sizeof (struct dep));
+      dep = alloc_dep ();
       dep->ignore_mtime = d->ignore_mtime;
-      dep->staticpattern = 0;
-      dep->need_2nd_expansion = 0;
       s = d->name; /* Hijacking the name. */
       d->name = 0;
       if (recursions == 0)
        {
-         dep->name = 0;
          dep->file = lookup_file (s);
          if (dep->file == 0)
            /* enter_file consumes S's storage.  */
@@ -883,9 +879,8 @@ pattern_search (struct file *file, int archive,
       else
        {
          dep->name = s;
-         dep->file = 0;
-         dep->changed = 0;
        }
+
       if (d->intermediate_file == 0 && tryrules[foundrule]->terminal)
        {
          /* If the file actually existed (was not an intermediate file),
@@ -943,11 +938,9 @@ pattern_search (struct file *file, int archive,
       if (i != matches[foundrule])
        {
          struct file *f;
-         struct dep *new = (struct dep *) xmalloc (sizeof (struct dep));
+         struct dep *new = alloc_dep ();
+
          /* GKM FIMXE: handle '|' here too */
-         new->ignore_mtime = 0;
-          new->staticpattern = 0;
-         new->need_2nd_expansion = 0;
          new->name = p = (char *) xmalloc (rule->lens[i] + fullstemlen + 1);
          bcopy (rule->targets[i], p,
                 rule->suffixes[i] - rule->targets[i] - 1);
diff --git a/main.c b/main.c
index a645e44c272bfa2f2e51f994ddc0a237451068b9..53a2e2ea43dd8b1c4bce5480e8541f0b5fabfa4b 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1850,7 +1850,7 @@ main (int argc, char **argv, char **envp)
                        last->next = d->next;
 
                      /* Free the storage.  */
-                     free ((char *) d);
+                      free_dep (d);
 
                      d = last == 0 ? read_makefiles : last->next;
 
@@ -2172,12 +2172,7 @@ main (int argc, char **argv, char **envp)
                   }
               }
 
-            goals = (struct dep *) xmalloc (sizeof (struct dep));
-            goals->next = 0;
-            goals->name = 0;
-            goals->ignore_mtime = 0;
-            goals->staticpattern = 0;
-            goals->need_2nd_expansion = 0;
+            goals = alloc_dep ();
             goals->file = default_goal_file;
           }
       }
@@ -2333,19 +2328,16 @@ handle_non_switch_argument (char *arg, int env)
 
       if (goals == 0)
        {
-         goals = (struct dep *) xmalloc (sizeof (struct dep));
+         goals = alloc_dep ();
          lastgoal = goals;
        }
       else
        {
-         lastgoal->next = (struct dep *) xmalloc (sizeof (struct dep));
+         lastgoal->next = alloc_dep ();
          lastgoal = lastgoal->next;
        }
-      lastgoal->name = 0;
+
       lastgoal->file = f;
-      lastgoal->ignore_mtime = 0;
-      lastgoal->staticpattern = 0;
-      lastgoal->need_2nd_expansion = 0;
 
       {
         /* Add this target name to the MAKECMDGOALS variable. */
diff --git a/misc.c b/misc.c
index 43df799ad6270a59c3d0ebf25527d201fa5f6f7d..082bcc67cc043c48b16660b496168b2ccd286e74 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -479,6 +479,32 @@ find_next_token (char **ptr, unsigned int *lengthptr)
   return p;
 }
 \f
+
+/* Allocate a new `struct dep' with all fields initialized to 0.   */
+
+struct dep *
+alloc_dep ()
+{
+  struct dep *d = (struct dep *) xmalloc (sizeof (struct dep));
+  bzero ((char *) d, sizeof (struct dep));
+  return d;
+}
+
+
+/* Free `struct dep' along with `name' and `stem'.   */
+
+void
+free_dep (struct dep *d)
+{
+  if (d->name != 0)
+    free (d->name);
+
+  if (d->stem != 0)
+    free (d->stem);
+
+  free ((char *)d);
+}
+
 /* Copy a chain of `struct dep', making a new chain
    with the same contents as the old one.  */
 
@@ -493,8 +519,12 @@ copy_dep_chain (const struct dep *d)
     {
       c = (struct dep *) xmalloc (sizeof (struct dep));
       bcopy ((char *) d, (char *) c, sizeof (struct dep));
+
       if (c->name != 0)
        c->name = xstrdup (c->name);
+      if (c->stem != 0)
+       c->stem = xstrdup (c->stem);
+
       c->next = 0;
       if (firstnew == 0)
        firstnew = lastnew = c;
@@ -516,14 +546,12 @@ free_dep_chain (struct dep *d)
     {
       struct dep *df = d;
       d = d->next;
-
-      free (df->name);
-      free ((char *)df);
+      free_dep (df);
     }
 }
 \f
 /* Free a chain of `struct nameseq'. Each nameseq->name is freed
-   as well.  Can be used on `struct dep' chains.*/
+   as well.  For `struct dep' chains use free_dep_chain.  */
 
 void
 free_ns_chain (struct nameseq *n)
diff --git a/read.c b/read.c
index 0c78c7f482946bbe36bcd3f948c7cbc46da1667b..f6e89861eb2465b99cb6a07bc840d4deec8aeb8d 100644 (file)
--- a/read.c
+++ b/read.c
@@ -248,13 +248,9 @@ read_all_makefiles (char **makefiles)
            tail = tail->next;
          for (p = default_makefiles; *p != 0; ++p)
            {
-             struct dep *d = (struct dep *) xmalloc (sizeof (struct dep));
-             d->name = 0;
+             struct dep *d = alloc_dep ();
              d->file = enter_file (*p);
              d->file->dontcare = 1;
-              d->ignore_mtime = 0;
-              d->staticpattern = 0;
-              d->need_2nd_expansion = 0;
              /* Tell update_goal_chain to bail out as soon as this file is
                 made, and main not to die if we can't make this file.  */
              d->changed = RM_DONTCARE;
@@ -366,18 +362,14 @@ eval_makefile (char *filename, int flags)
     }
 
   /* Add FILENAME to the chain of read makefiles.  */
-  deps = (struct dep *) xmalloc (sizeof (struct dep));
+  deps = alloc_dep ();
   deps->next = read_makefiles;
   read_makefiles = deps;
-  deps->name = 0;
   deps->file = lookup_file (filename);
   if (deps->file == 0)
     deps->file = enter_file (xstrdup (filename));
   filename = deps->file->name;
   deps->changed = flags;
-  deps->ignore_mtime = 0;
-  deps->staticpattern = 0;
-  deps->need_2nd_expansion = 0;
   if (flags & RM_DONTCARE)
     deps->file->dontcare = 1;
 
@@ -1177,14 +1169,8 @@ eval (struct ebuffer *ebuf, int set_default)
         if (beg <= end && *beg != '\0')
           {
             /* Put all the prerequisites here; they'll be parsed later.  */
-            deps = (struct dep *) xmalloc (sizeof (struct dep));
-            deps->next = 0;
+            deps = alloc_dep ();
             deps->name = savestring (beg, end - beg + 1);
-            deps->file = 0;
-            deps->changed = 0;
-            deps->ignore_mtime = 0;
-            deps->staticpattern = 0;
-            deps->need_2nd_expansion = 0;
           }
         else
           deps = 0;
@@ -2111,7 +2097,10 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
                                      pattern_percent+1, percent+1);
           f->stem = savestring (buffer, o - buffer);
           if (this)
-            this->staticpattern = 1;
+            {
+              this->staticpattern = 1;
+              this->stem = xstrdup (f->stem);
+            }
         }
 
       /* Free name if not needed further.  */
index da231b4a0a465e092321e54a8839af55d9cf0265..2dfade3c57332b8f21a713401d1d6416b6e0c480 100644 (file)
--- a/remake.c
+++ b/remake.c
@@ -994,13 +994,13 @@ check_dep (struct file *file, unsigned int depth,
                  if (lastd == 0)
                    {
                      file->deps = d->next;
-                     free ((char *) d);
+                      free_dep (d);
                      d = file->deps;
                    }
                  else
                    {
                      lastd->next = d->next;
-                     free ((char *) d);
+                      free_dep (d);
                      d = lastd->next;
                    }
                  continue;
diff --git a/rule.c b/rule.c
index 527b5b0cf1f8a161edd56c9a7f4ee0e19c5a6905..e988db5bbfd127d43c24c896d73dbe51db2a494a 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -201,12 +201,8 @@ convert_suffix_rule (char *target, char *source, struct commands *cmds)
       depname = xmalloc (1 + len + 1);
       depname[0] = '%';
       bcopy (source, depname + 1, len + 1);
-      deps = (struct dep *) xmalloc (sizeof (struct dep));
-      deps->next = 0;
+      deps = alloc_dep ();
       deps->name = depname;
-      deps->ignore_mtime = 0;
-      deps->staticpattern = 0;
-      deps->need_2nd_expansion = 0;
     }
 
   create_pattern_rule (names, percents, 0, deps, cmds, 0);
@@ -428,7 +424,8 @@ freerule (struct rule *rule, struct rule *lastrule)
       t = dep->next;
       /* We might leak dep->name here, but I'm not sure how to fix this: I
          think that pointer might be shared (e.g., in the file hash?)  */
-      free ((char *) dep);
+      dep->name = 0; /* Make sure free_dep does not free name.  */
+      free_dep (dep);
       dep = t;
     }
 
index 05dfaeca0329e870dba207d1c0195ac3877e9fa7..67cf900eafaf77284ddaf81571b7f19383834db0 100644 (file)
@@ -1,3 +1,7 @@
+2006-03-17  Boris Kolpackov  <boris@kolpackov.net>
+
+       * scripts/features/statipattrules: Add tests for bug #16053.
+
 2006-03-09  Paul Smith  <psmith@gnu.org>
 
        * scripts/features/escape: Use "pre:" not "p:" to avoid conflicts
index 429b56a18dbc54fdc3dd2247a142899f652385cf..3f363defb1f0749a722c0adca8a07483ef5ab68d 100644 (file)
@@ -67,4 +67,45 @@ foo.baz: ;@:
 ',
               '', '');
 
+
+# TEST #6: make sure the second stem does not overwrite the first
+#          perprerequisite's stem (Savannah bug #16053).
+#
+run_make_test('
+all.foo.bar: %.foo.bar: %.one
+
+all.foo.bar: %.bar: %.two
+
+all.foo.bar:
+       @echo $*
+       @echo $^
+
+.DEFAULT:;@:
+',
+'',
+'all.foo
+all.one all.foo.two');
+
+
+# TEST #7: make sure the second stem does not overwrite the first
+#          perprerequisite's stem when second expansion is enabled
+#          (Savannah bug #16053).
+#
+run_make_test('
+.SECONDEXPANSION:
+
+all.foo.bar: %.foo.bar: %.one $$*-one
+
+all.foo.bar: %.bar: %.two $$*-two
+
+all.foo.bar:
+       @echo $*
+       @echo $^
+
+.DEFAULT:;@:
+',
+'',
+'all.foo
+all.one all-one all.foo.two all.foo-two');
+
 1;