m4-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

plug some memory bugs


From: Eric Blake
Subject: plug some memory bugs
Date: Fri, 1 Sep 2006 23:09:06 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

It's a wonder that CVS head even ran; it has had a latent bug since Oct 2003 
that caused out-of-bounds writes to the heap on bootup, even before option 
processing starts!  I also narrowed down why this crashes:
$ echo 'define(bar,1)define(baz,2)renamesyms(^ba.,baa)'|m4

Our hash table is not prepared to handle multiple entries with equivalent keys 
(and even documented this, but not very well - node_insert mentioned that 
inserting equal keys should just shadow the older entry, but bucket_insert 
mentioned that relative ordering is not preserved).  When we go to traverse the 
table for cleanup, we do a lookup for the shadowed "baa" key being visited by 
the iterator, but find the other "baa" key in the table, and then try to delete 
the element not pointed to by the iterator, which breaks the iteration.  I 
added some assertion framework that catches this and other hash-table no-nos.  
This also fixes some potential memory leaks, if any hash table iterator 
callback ever returns non-NULL.  Now it is a question of how we should fix 
renamesyms to quit mapping multiple macros to the same name, and ending up with 
multiple entries in the hashtable; or add an API so that it is easier to delete 
the element being visited by the iterator without having to repeat a key lookup 
(and perhaps find the wrong entry); or something else altogether.

Meanwhile, we were compiling getopt twice.  And finally, I consistently used 
the keyword "module" for all tests in the testsuite that depend on dynamic 
modules (and which fail when ./configure --disable-shared).

2006-09-01  Eric Blake  <address@hidden>

        * m4/m4.c (m4_create): Fix latent bug since 2003-10-08.
        * m4/hash.h (m4_free_hash_iterator): New prototype.
        * m4/hash.c (struct m4_hash) [!NDEBUG]: Add iter member, to
        ensure we don't do unsafe things while iterating.
        (HASH_ITER, ITER_CHAIN): New accessor macros.
        (m4_hash_new, m4_hash_resize, maybe_grow): Fix malloc typing bug.
        (m4_hash_delete, m4_hash_insert): Unsafe while iterating.
        (m4_hash_remove) [!NDEBUG]: Enforce safety while iterating.
        (m4_get_hash_iterator_next) [!NDEBUG]: Track current iterators,
        to catch unsafe actions.
        (m4_free_hash_iterator): New function, to avoid memory leaks, and
        when debugging, to track safe actions.
        (m4_hash_apply): Avoid memory leak.
        * m4/symtab.c (m4_symtab_apply): Likewise.
        * ltdl/m4/gnulib-cache.m4: Remove getopt from here; it is pulled
        in manually to src/ for now.
        * tests/builtins.at (gmp): Add keyword module.
        * tests/modules.at (Freezing modules, modules: shadow)
        (modules: unload, modules: importing, modules: trace): Likewise.

Index: ltdl/m4/gnulib-cache.m4
===================================================================
RCS file: /sources/m4/m4/ltdl/m4/gnulib-cache.m4,v
retrieving revision 1.9
diff -u -r1.9 gnulib-cache.m4
--- ltdl/m4/gnulib-cache.m4     25 Aug 2006 19:23:02 -0000      1.9
+++ ltdl/m4/gnulib-cache.m4     1 Sep 2006 23:01:45 -0000
@@ -15,15 +15,17 @@
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --lib=libgnu --source-base=gnu --m4-
base=ltdl/m4 --doc-base=doc --aux-dir=ltdl/config --libtool --macro-prefix=M4 
assert binary-io cloexec close-stream dirname error exit fdl filenamecat fopen-
safer free gendocs getopt gettext gnupload mkstemp obstack progname regex 
regexprops-generic stdbool stdlib-safer strtol unlocked-io verror xalloc xalloc-
die xstrndup xvasprintf
+#   gnulib-tool --import --dir=. --lib=libgnu --source-base=gnu --m4-
base=ltdl/m4 --doc-base=doc --aux-dir=ltdl/config --libtool --macro-prefix=M4 
assert binary-io cloexec close-stream dirname error exit fdl filenamecat fopen-
safer free gendocs gettext gnupload mkstemp obstack progname regex regexprops-
generic stdbool stdlib-safer strtol unlocked-io verror xalloc xalloc-die 
xstrndup xvasprintf
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
-gl_MODULES([assert binary-io cloexec close-stream dirname error exit fdl 
filenamecat fopen-safer free gendocs getopt gettext gnupload mkstemp obstack 
progname regex regexprops-generic stdbool stdlib-safer strtol unlocked-io 
verror xalloc xalloc-die xstrndup xvasprintf])
+gl_LOCAL_DIR([])
+gl_MODULES([assert binary-io cloexec close-stream dirname error exit fdl 
filenamecat fopen-safer free gendocs gettext gnupload mkstemp obstack progname 
regex regexprops-generic stdbool stdlib-safer strtol unlocked-io verror xalloc 
xalloc-die xstrndup xvasprintf])
 gl_AVOID([])
 gl_SOURCE_BASE([gnu])
 gl_M4_BASE([ltdl/m4])
 gl_DOC_BASE([doc])
 gl_TESTS_BASE([tests])
 gl_LIB([libgnu])
+gl_MAKEFILE_NAME([])
 gl_LIBTOOL
 gl_MACRO_PREFIX([M4])
Index: m4/hash.c
===================================================================
RCS file: /sources/m4/m4/m4/hash.c,v
retrieving revision 1.19
diff -u -r1.19 hash.c
--- m4/hash.c   28 Jul 2006 01:49:37 -0000      1.19
+++ m4/hash.c   1 Sep 2006 23:01:45 -0000
@@ -37,6 +37,9 @@
   m4_hash_hash_func *hash_func;
   m4_hash_cmp_func *cmp_func;
   hash_node **buckets;
+#ifndef NDEBUG
+  m4_hash_iterator *iter;      /* current iterator */
+#endif
 };
 
 struct hash_node
@@ -47,6 +50,17 @@
 };
 
 
+struct m4_hash_iterator
+{
+  const m4_hash *hash;         /* contains the buckets */
+  hash_node *  place;          /* the node we are about to return */
+  hash_node *  next;           /* the next node, incase PLACE is removed */
+  size_t       next_bucket;    /* the next bucket index following NEXT */
+#ifndef NDEBUG
+  m4_hash_iterator *chain;     /* multiple iterators visiting one hash */
+#endif
+};
+
 
 #define HASH_SIZE(hash)                ((hash)->size)
 #define HASH_LENGTH(hash)      ((hash)->length)
@@ -58,13 +72,28 @@
 #define NODE_KEY(node) ((node)->key)
 #define NODE_VALUE(node)       ((node)->value)
 
+#define ITERATOR_HASH(i)       ((i)->hash)
+#define ITERATOR_PLACE(i)      ((i)->place)
+#define ITERATOR_NEXT(i)       ((i)->next)
+#define ITERATOR_NEXT_BUCKET(i)        ((i)->next_bucket)
+
+#define ITERATOR_NEXT_NEXT(i)   NODE_NEXT (ITERATOR_PLACE (i))
+
 /* Helper macros. */
 #define BUCKET_NTH(hash, n)    (HASH_BUCKETS (hash)[n])
 #define BUCKET_COUNT(hash, key)                                        \
-       ((*HASH_HASH_FUNC(hash))(key) % HASH_SIZE(hash))
+       ((*HASH_HASH_FUNC (hash))(key) % HASH_SIZE (hash))
 #define BUCKET_KEY(hash, key)                                  \
        (BUCKET_NTH ((hash), BUCKET_COUNT ((hash), (key))))
 
+/* Debugging macros.  */
+#ifdef NDEBUG
+# define HASH_ITER(hash)       0
+# define ITER_CHAIN(iter)      0
+#else
+# define HASH_ITER(hash)       (((m4_hash *) hash)->iter)
+# define ITER_CHAIN(iter)      ((iter)->chain)
+#endif
 
 
 static void            bucket_insert   (m4_hash *hash, hash_node *bucket);
@@ -77,7 +106,7 @@
 
 
 
-static hash_node *free_list = 0;
+static hash_node *free_list = NULL;
 
 
 
@@ -99,9 +128,12 @@
   hash                 = xmalloc (sizeof *hash);
   HASH_SIZE (hash)     = size;
   HASH_LENGTH (hash)   = 0;
-  HASH_BUCKETS (hash)  = xcalloc (size, sizeof HASH_BUCKETS (hash));
+  HASH_BUCKETS (hash)  = xcalloc (size, sizeof *HASH_BUCKETS (hash));
   HASH_HASH_FUNC (hash)        = hash_func;
   HASH_CMP_FUNC (hash) = cmp_func;
+#ifndef NDEBUG
+  HASH_ITER (hash)     = NULL;
+#endif
 
   return hash;
 }
@@ -123,15 +155,17 @@
 }
 
 /* Recycle each of the nodes in HASH onto the free list, and release
-   the rest of the memory used by the table.  Memory addressed by
-   the recycled nodes is _NOT_ freed:  this needs to be done manually
-   to prevent memory leaks.  */
+   the rest of the memory used by the table.  Memory addressed by the
+   recycled nodes is _NOT_ freed: this needs to be done manually to
+   prevent memory leaks.  This is not safe to call while HASH is being
+   iterated.  */
 void
 m4_hash_delete (m4_hash *hash)
 {
   size_t i;
 
   assert (hash);
+  assert (!HASH_ITER (hash));
 
   for (i = 0; i < HASH_SIZE (hash); ++i)
     if (BUCKET_NTH (hash, i))
@@ -154,16 +188,16 @@
 
   for (node = BUCKET_NTH (hash, i); node->next; node = NODE_NEXT (node))
     {
-      assert (NODE_KEY(node) == 0);
+      assert (NODE_KEY (node) == NULL);
       --HASH_LENGTH (hash);
     }
 
-  assert (NODE_KEY(node) == 0);
+  assert (NODE_KEY (node) == NULL);
   --HASH_LENGTH (hash);
 
   NODE_NEXT (node)     = free_list;
   free_list            = BUCKET_NTH (hash, i);
-  BUCKET_NTH (hash, i) = 0;
+  BUCKET_NTH (hash, i) = NULL;
 }
 
 /* Create and initialise a new node with KEY and VALUE, by reusing a
@@ -171,7 +205,7 @@
 static hash_node *
 node_new (const void *key, void *value)
 {
-  hash_node *node = 0;
+  hash_node *node = NULL;
 
   if (free_list)
     {
@@ -185,7 +219,7 @@
 
   assert (node);
 
-  NODE_NEXT  (node)    = 0;
+  NODE_NEXT  (node)    = NULL;
   NODE_KEY   (node)    = key;
   NODE_VALUE (node)    = value;
 
@@ -197,7 +231,7 @@
 node_delete (m4_hash *hash, hash_node *node)
 {
   assert (node);
-  assert (NODE_KEY(node) == 0);
+  assert (NODE_KEY (node) == NULL);
 
   NODE_NEXT (node)     = free_list;
   free_list            = node;
@@ -205,15 +239,18 @@
   --HASH_LENGTH (hash);
 }
 
-/* Create a new entry in HASH with KEY and VALUE, making use of
-   nodes in the free list if possible, and potentially growing
-   the size of the table if node density is too high.  */
+/* Create a new entry in HASH with KEY and VALUE, making use of nodes
+   in the free list if possible, and potentially growing the size of
+   the table if node density is too high.  This is not safe to call
+   while HASH is being iterated.  Currently, it is not safe to call
+   this if another entry already matches KEY.  */
 const void *
 m4_hash_insert (m4_hash *hash, const void *key, void *value)
 {
   hash_node *node;
 
   assert (hash);
+  assert (!HASH_ITER (hash));
 
   node = node_new (key, value);
   node_insert (hash, node);
@@ -233,7 +270,7 @@
 
   assert (hash);
   assert (node);
-  assert (NODE_NEXT (node) == 0);
+  assert (NODE_NEXT (node) == NULL);
 
   n = BUCKET_COUNT (hash, NODE_KEY (node));
   NODE_NEXT (node)     = BUCKET_NTH (hash, n);
@@ -242,21 +279,32 @@
   ++HASH_LENGTH (hash);
 }
 
-/* Remove from HASH, the first node with key KEY; comparing keys
-   with HASH's cmp_func.  Any nodes with the same KEY previously
-   hidden by the removed node will become visible again.  The key
-   field of the removed node is returned.  */
+/* Remove from HASH, the first node with key KEY; comparing keys with
+   HASH's cmp_func.  Any nodes with the same KEY previously hidden by
+   the removed node will become visible again.  The key field of the
+   removed node is returned, or the original KEY If there was no
+   match.  This is unsafe if multiple iterators are visiting HASH, or
+   when a lone iterator is visiting on a different key.  */
 void *
 m4_hash_remove (m4_hash *hash, const void *key)
 {
   size_t n;
 
+#ifndef NDEBUG
+  m4_hash_iterator *iter = HASH_ITER (hash);
+
   assert (hash);
+  if (HASH_ITER (hash))
+    {
+      assert (!ITER_CHAIN (iter));
+      assert (ITERATOR_PLACE (iter));
+    }
+#endif
 
   n = BUCKET_COUNT (hash, key);
 
   {
-    hash_node *node = 0;
+    hash_node *node = NULL;
 
     do
       {
@@ -271,7 +319,9 @@
 
            key = NODE_KEY (next);
 #ifndef NDEBUG
-           NODE_KEY (next) = 0;
+           if (iter)
+             assert (ITERATOR_PLACE (iter) == next);
+           NODE_KEY (next) = NULL;
 #endif
            node_delete (hash, next);
            break;
@@ -284,11 +334,12 @@
   return (void *) key;
 }
 
-/* Return the address of the value field of the first node in
-   HASH that has a matching KEY.  The address is returned so that
-   an explicit 0 value can be distinguished from a failed lookup
-   (also 0).  Fortuitously for M4, this also means that the value
-   field can be changed `in situ' to implement a value stack.  */
+/* Return the address of the value field of the first node in HASH
+   that has a matching KEY.  The address is returned so that an
+   explicit NULL value can be distinguished from a failed lookup (also
+   NULL).  Fortuitously for M4, this also means that the value field
+   can be changed `in situ' to implement a value stack.  Safe to call
+   even when an iterator is in force.  */
 void **
 m4_hash_lookup (m4_hash *hash, const void *key)
 {
@@ -298,7 +349,7 @@
 
   node = node_lookup (hash, key);
 
-  return node ? &NODE_VALUE (node) : 0;
+  return node ? &NODE_VALUE (node) : NULL;
 }
 
 /* Return the first node in HASH that has a matching KEY.  */
@@ -317,7 +368,8 @@
   return node;
 }
 
-/* How many entries are currently contained by HASH.  */
+/* How many entries are currently contained by HASH.  Safe to call
+   even during an interation.  */
 size_t
 m4_get_hash_length (m4_hash *hash)
 {
@@ -334,7 +386,8 @@
    to set a smaller or larger initial size if you know in advance what
    order of magnitude of entries will be in the table.  Be aware that
    the efficiency of the lookup and grow features require that the size
-   always be 1 less than a power of 2.  */
+   always be 1 less than a power of 2.  Unsafe if HASH is being visited
+   by an iterator.  */
 void
 m4_hash_resize (m4_hash *hash, size_t size)
 {
@@ -342,12 +395,13 @@
   size_t original_size;
 
   assert (hash);
+  assert (!HASH_ITER (hash));
 
   original_size                = HASH_SIZE (hash);
   original_buckets     = HASH_BUCKETS (hash);
 
   HASH_SIZE (hash)     = size;
-  HASH_BUCKETS (hash)   = xcalloc (size, sizeof HASH_BUCKETS (hash));
+  HASH_BUCKETS (hash)   = xcalloc (size, sizeof *HASH_BUCKETS (hash));
 
   {
     size_t i;
@@ -377,8 +431,9 @@
       hash_node **original_buckets = HASH_BUCKETS (hash);
 
       /* HASH sizes are always 1 less than a power of 2.  */
-      HASH_SIZE (hash)    = (2* (1+ original_size)) -1;
-      HASH_BUCKETS (hash) = xcalloc (hash->size, sizeof HASH_BUCKETS (hash));
+      HASH_SIZE (hash)    = (2 * (1 + original_size)) -1;
+      HASH_BUCKETS (hash) = xcalloc (HASH_SIZE (hash),
+                                    sizeof *HASH_BUCKETS (hash));
 
       {
        size_t i;
@@ -392,7 +447,8 @@
 }
 
 /* Insert each node in BUCKET into HASH.  Relative ordering of nodes
-   is not preserved.  */
+   is not preserved.  This would need to change if we were to
+   guarantee relative ordering within a bucket for identical keys.  */
 static void
 bucket_insert (m4_hash *hash, hash_node *bucket)
 {
@@ -404,7 +460,7 @@
       hash_node *next = NODE_NEXT (bucket);
 
       /* Break link to rest of the bucket before reinserting.  */
-      NODE_NEXT (bucket) = 0;
+      NODE_NEXT (bucket) = NULL;
       node_insert (hash, bucket);
 
       bucket = next;
@@ -412,6 +468,9 @@
   while (bucket);
 }
 
+/* Reclaim all memory used by free nodes.  Safe to call at any time,
+   although only worth calling at program shutdown to verify no
+   leaks.  */
 void
 m4_hash_exit (void)
 {
@@ -425,21 +484,14 @@
 
 
 
-struct m4_hash_iterator
-{
-  const m4_hash *hash;         /* contains the buckets */
-  hash_node *  place;          /* the node we are about to return */
-  hash_node *  next;           /* the next node, incase PLACE is removed */
-  size_t       next_bucket;    /* the next bucket index following NEXT */
-};
-
-#define ITERATOR_HASH(i)       ((i)->hash)
-#define ITERATOR_PLACE(i)      ((i)->place)
-#define ITERATOR_NEXT(i)       ((i)->next)
-#define ITERATOR_NEXT_BUCKET(i)        ((i)->next_bucket)
-
-#define ITERATOR_NEXT_NEXT(i)   NODE_NEXT (ITERATOR_PLACE (i))
-
+/* Iterate over a given HASH.  Start with PLACE being NULL, then
+   repeat with PLACE being the previous return value.  The return
+   value is the current location of the iterator, or NULL when the
+   walk is complete.  Call m4_free_hash_iterator to abort iteration.
+   During the iteration, it is safe to search the list, and if no
+   other iterator is active, it is safe to remove the key pointed to
+   by this iterator.  All other actions that modify HASH are
+   unsafe.  */
 m4_hash_iterator *
 m4_get_hash_iterator_next (const m4_hash *hash, m4_hash_iterator *place)
 {
@@ -451,6 +503,10 @@
     {
       place = xzalloc (sizeof *place);
       ITERATOR_HASH (place) = hash;
+#ifndef NDEBUG
+      ITER_CHAIN (place) = HASH_ITER (hash);
+      HASH_ITER (hash) = place;
+#endif
     }
 
  next:
@@ -465,7 +521,7 @@
     {
       /* Find the next non-empty bucket.  */
       while ((ITERATOR_NEXT_BUCKET (place) < HASH_SIZE (hash))
-        && (BUCKET_NTH (hash, ITERATOR_NEXT_BUCKET (place)) == 0))
+        && (BUCKET_NTH (hash, ITERATOR_NEXT_BUCKET (place)) == NULL))
        {
          ++ITERATOR_NEXT_BUCKET (place);
        }
@@ -477,7 +533,7 @@
            = BUCKET_NTH (hash, ITERATOR_NEXT_BUCKET (place));
        }
       else
-       ITERATOR_NEXT (place) = 0;
+       ITERATOR_NEXT (place) = NULL;
 
       /* Advance the `next' reference.  */
       ++ITERATOR_NEXT_BUCKET (place);
@@ -486,8 +542,8 @@
   /* If there are no more nodes to return, recycle the iterator memory.  */
   if (! (ITERATOR_PLACE (place) || ITERATOR_NEXT (place)))
     {
-      free (place);
-      return 0;
+      m4_free_hash_iterator (hash, place);
+      return NULL;
     }
 
   /* On the first call we need to put the 1st node in PLACE and
@@ -500,6 +556,38 @@
   return place;
 }
 
+/* Clean up the iterator PLACE within HASH when aborting an iteration
+   early.  */
+void
+m4_free_hash_iterator (const m4_hash *hash, m4_hash_iterator *place)
+{
+#ifndef NDEBUG
+  m4_hash_iterator *iter = NULL;
+  m4_hash_iterator *next;
+
+  assert (hash);
+  assert (place && (ITERATOR_HASH (place) == hash));
+
+  do
+    {
+      next = iter ? ITER_CHAIN (iter) : HASH_ITER (hash);
+      if (place == next)
+       {
+         if (iter)
+           ITER_CHAIN (iter) = ITER_CHAIN (next);
+         else
+           HASH_ITER (hash) = ITER_CHAIN (next);
+         break;
+       }
+      iter = next;
+    }
+  while (iter);
+  assert (next);
+#endif
+  free (place);
+}
+
+/* Return the key being visited by the iterator PLACE.  */
 const void *
 m4_get_hash_iterator_key (m4_hash_iterator *place)
 {
@@ -508,6 +596,7 @@
   return NODE_KEY (ITERATOR_PLACE (place));
 }
 
+/* Return the value being visited by the iterator PLACE.  */
 void *
 m4_get_hash_iterator_value (m4_hash_iterator *place)
 {
@@ -517,10 +606,12 @@
 }
 
 /* The following function is used for the cases where we want to do
-   something to each and every entry in HASH.  This function
-   traverses the hash table, and calls a specified function FUNC for
-   each entry in the table.  FUNC is called with a pointer to the
-   entry key, value, and the passed DATA argument.  */
+   something to each and every entry in HASH.  This function traverses
+   the hash table, and calls a specified function FUNC for each entry
+   in the table.  FUNC is called with a pointer to the entry key,
+   value, and the passed DATA argument.  If FUNC returns non-NULL,
+   abort the iteration and return that value; a return of NULL implies
+   success on all entries.  */
 void *
 m4_hash_apply (m4_hash *hash, m4_hash_apply_func *func, void *userdata)
 {
@@ -536,7 +627,10 @@
                        m4_get_hash_iterator_value (place), userdata);
 
       if (result != NULL)
-       break;
+       {
+         m4_free_hash_iterator (hash, place);
+         break;
+       }
     }
 
   return result;
Index: m4/hash.h
===================================================================
RCS file: /sources/m4/m4/m4/hash.h,v
retrieving revision 1.11
diff -u -r1.11 hash.h
--- m4/hash.h   1 May 2005 11:10:05 -0000       1.11
+++ m4/hash.h   1 Sep 2006 23:01:45 -0000
@@ -1,5 +1,5 @@
 /* GNU m4 -- A simple macro processor
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2006 Free Software Foundation, Inc.
    Written by Gary V. Vaughan <address@hidden>
 
    This program is free software; you can redistribute it and/or modify
@@ -71,6 +71,8 @@
 extern void *           m4_get_hash_iterator_value (m4_hash_iterator *place);
 extern m4_hash_iterator *m4_get_hash_iterator_next  (const m4_hash *hash,
                                                     m4_hash_iterator *place);
+extern void             m4_free_hash_iterator      (const m4_hash *hash,
+                                                    m4_hash_iterator *place);
 
 
 END_C_DECLS
Index: m4/m4.c
===================================================================
RCS file: /sources/m4/m4/m4/m4.c,v
retrieving revision 1.17
diff -u -r1.17 m4.c
--- m4/m4.c     25 Aug 2006 19:23:02 -0000      1.17
+++ m4/m4.c     1 Sep 2006 23:01:45 -0000
@@ -36,7 +36,7 @@
 
   context->nesting_limit = DEFAULT_NESTING_LIMIT;
 
-  context->search_path  = xzalloc (sizeof context->search_path);
+  context->search_path  = xzalloc (sizeof *context->search_path);
   m4__include_init (context);
 
   return context;
Index: m4/symtab.c
===================================================================
RCS file: /sources/m4/m4/m4/symtab.c,v
retrieving revision 1.57
diff -u -r1.57 symtab.c
--- m4/symtab.c 30 Aug 2006 04:25:42 -0000      1.57
+++ m4/symtab.c 1 Sep 2006 23:01:45 -0000
@@ -105,7 +105,10 @@
                        userdata);
 
       if (result != NULL)
-       break;
+       {
+         m4_free_hash_iterator (symtab->table, place);
+         break;
+       }
     }
 
   return result;
Index: tests/builtins.at
===================================================================
RCS file: /sources/m4/m4/tests/builtins.at,v
retrieving revision 1.16
diff -u -r1.16 builtins.at
--- tests/builtins.at   31 Aug 2006 03:21:35 -0000      1.16
+++ tests/builtins.at   1 Sep 2006 23:01:45 -0000
@@ -176,6 +176,7 @@
 ## --- ##
 
 AT_SETUP([gmp])
+AT_KEYWORDS([module])
 
 # cannot perform test without --with-gmp
 AT_CHECK([test "$USE_GMP" = yes || exit 77])
Index: tests/modules.at
===================================================================
RCS file: /sources/m4/m4/tests/modules.at,v
retrieving revision 1.18
diff -u -r1.18 modules.at
--- tests/modules.at    31 Aug 2006 03:21:36 -0000      1.18
+++ tests/modules.at    1 Sep 2006 23:01:45 -0000
@@ -26,6 +26,7 @@
 
 AT_SETUP([Freezing modules])
 AT_KEYWORDS([frozen])
+AT_KEYWORDS([module])
 
 AT_DATA([[frozen.m4]],
 [[divert(1)dnl
@@ -134,6 +135,7 @@
 ## ------ ##
 
 AT_SETUP([modules: shadow])
+AT_KEYWORDS([module])
 
 AT_DATA([[input.m4]],
 [[# no modules loaded yet
@@ -274,6 +276,7 @@
 ## ------ ##
 
 AT_SETUP([modules: unload])
+AT_KEYWORDS([module])
 
 AT_DATA([[input.m4]],
 [[test
@@ -347,6 +350,7 @@
 # from the first command:
 
 AT_SETUP([modules: importing])
+AT_KEYWORDS([module])
 
 AT_DATA([[input.m4]],
 [[import
@@ -405,6 +409,7 @@
 # memory and then redefined by a subsequent load.
 
 AT_SETUP([modules: trace])
+AT_KEYWORDS([module])
 
 AT_DATA([[input.m4]],
 [[test






reply via email to

[Prev in Thread] Current Thread [Next in Thread]