~ubuntu-branches/ubuntu/lucid/eglibc/lucid-updates

« back to all changes in this revision

Viewing changes to debian/patches/any/glibc-CVE-2011-1071.patch

  • Committer: Package Import Robot
  • Author(s): Steve Beattie
  • Date: 2012-03-07 10:28:32 UTC
  • mfrom: (42.1.3 lucid-security)
  • Revision ID: package-import@ubuntu.com-20120307102832-om8ercp049cypxlc
Tags: 2.11.1-0ubuntu7.10
* SECURITY UPDATE: timezone header parsing integer overflow (LP: #906961)
  - debian/patches/any/glibc-CVE-2009-5029.patch: Check values from
    TZ file header
  - CVE-2009-5029
* SECURITY UPDATE: memory consumption denial of service in fnmatch
  - debian/patches/any/glibc-CVE-2011-1071.patch: avoid too much
    stack use in fnmatch.
  - CVE-2011-1071
* SECURITY UPDATE: /etc/mtab corruption denial of service
  - debian/patches/any/glibc-CVE-2011-1089.patch: Report write
    error in addmnt even for cached streams
  - CVE-2011-1089
* SECURITY UPDATE: insufficient locale environment sanitization
  - debian/patches/any/glibc-CVE-2011-1095.patch: escape contents of
    LANG environment variable.
  - CVE-2011-1095
* SECURITY UPDATE: ld.so insecure handling of privileged programs'
  RPATHs with $ORIGIN
  - debian/patches/any/glibc-CVE-2011-1658.patch: improve handling of
    RPATH and ORIGIN
  - CVE-2011-1658
* SECURITY UPDATE: fnmatch integer overflow
  - debian/patches/any/glibc-CVE-2011-1659.patch: check size of
    pattern in wide character representation
  - CVE-2011-1659
* SECURITY UPDATE: signedness bug in memcpy_ssse3
  - debian/patches/any/glibc-CVE-2011-2702.patch: use unsigned
    comparison instructions
  - CVE-2011-2702
* SECURITY UPDATE: DoS in RPC implementation (LP: #901716)
  - debian/patches/any/glibc-CVE-2011-4609.patch: nanosleep when too
    many open fds is detected
  - CVE-2011-4609
* SECURITY UPDATE: vfprintf nargs overflow leading to FORTIFY
  check bypass
  - debian/patches/any/glibc-CVE-2012-0864.patch: check for integer
    overflow
  - CVE-2012-0864
* debian/testsuite-checking/expected-results-x86_64-linux-gnu-libc,
  debian/testsuite-checking/expected-results-i686-linux-gnu-i386,
  debian/testsuite-checking/expected-results-arm-linux-gnueabi-libc:
  update for pre-existing testsuite failures that prevents FTBFS
  when the testsuite is enabled.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
From f15ce4d8dc139523fe0c273580b604b2453acba6 Mon Sep 17 00:00:00 2001
 
2
From: Ulrich Drepper <drepper@redhat.com>
 
3
Date: Mon, 9 Aug 2010 21:09:37 -0700
 
4
Subject: [PATCH] Avoid too much stack use in fnmatch.
 
5
 
 
6
From 8126d90480fa3e0c5c5cd0d02cb1c93174b45485 Mon Sep 17 00:00:00 2001
 
7
From: Ulrich Drepper <drepper@gmail.com>
 
8
Date: Fri, 18 Mar 2011 05:29:20 -0400
 
9
Subject: [PATCH 1/1] Check size of pattern in wide character
 
10
 representation in fnmatch.
 
11
 
 
12
  * posix/fnmatch.c (fnmatch): Check size of pattern in wide
 
13
    character representation.  Partly based on a patch by Tomas Hoger
 
14
    <thoger@redhat.com>.
 
15
 
 
16
CVE-2011-1071
 
17
 
 
18
[Ubuntu note: differs from upstream patch in that the changes to
 
19
 Changelog and NEWS file have been dropped to reduce conflicts.]
 
20
 
 
21
---
 
22
 posix/fnmatch.c      |   57 +++++++++++++++++-----
 
23
 posix/fnmatch_loop.c |  132 ++++++++++++++++++++++++++++++++-------------------
 
24
 2 files changed, 128 insertions(+), 61 deletions(-)
 
25
 
 
26
Index: b/posix/fnmatch.c
 
27
===================================================================
 
28
--- a/posix/fnmatch.c
 
29
+++ b/posix/fnmatch.c
 
30
@@ -1,4 +1,4 @@
 
31
-/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2002,2003,2007
 
32
+/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2002,2003,2007,2010
 
33
        Free Software Foundation, Inc.
 
34
    This file is part of the GNU C Library.
 
35
 
 
36
@@ -45,6 +45,12 @@
 
37
 # include <stdlib.h>
 
38
 #endif
 
39
 
 
40
+#ifdef _LIBC
 
41
+# include <alloca.h>
 
42
+#else
 
43
+# define alloca_account(size., var) alloca (size)
 
44
+#endif
 
45
+
 
46
 /* For platform which support the ISO C amendement 1 functionality we
 
47
    support user defined character classes.  */
 
48
 #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
 
49
@@ -334,8 +340,11 @@ fnmatch (pattern, string, flags)
 
50
       mbstate_t ps;
 
51
       size_t n;
 
52
       const char *p;
 
53
+      wchar_t *wpattern_malloc = NULL;
 
54
       wchar_t *wpattern;
 
55
+      wchar_t *wstring_malloc = NULL;
 
56
       wchar_t *wstring;
 
57
+      size_t alloca_used = 0;
 
58
 
 
59
       /* Convert the strings into wide characters.  */
 
60
       memset (&ps, '\0', sizeof (ps));
 
61
@@ -347,7 +356,8 @@ fnmatch (pattern, string, flags)
 
62
 #endif
 
63
       if (__builtin_expect (n < 1024, 1))
 
64
        {
 
65
-         wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
 
66
+         wpattern = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t),
 
67
+                                                alloca_used);
 
68
          n = mbsrtowcs (wpattern, &p, n + 1, &ps);
 
69
          if (__builtin_expect (n == (size_t) -1, 0))
 
70
            /* Something wrong.
 
71
@@ -369,8 +379,11 @@ fnmatch (pattern, string, flags)
 
72
               XXX Do we have to set `errno' to something which mbsrtows hasn't
 
73
               already done?  */
 
74
            return -1;
 
75
-         wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
 
76
+         wpattern_malloc = wpattern
 
77
+           = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t));
 
78
          assert (mbsinit (&ps));
 
79
+         if (wpattern == NULL)
 
80
+           return -2;
 
81
          (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
 
82
        }
 
83
 
 
84
@@ -383,13 +396,18 @@ fnmatch (pattern, string, flags)
 
85
       p = string;
 
86
       if (__builtin_expect (n < 1024, 1))
 
87
        {
 
88
-         wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
 
89
+         wstring = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t),
 
90
+                                               alloca_used);
 
91
          n = mbsrtowcs (wstring, &p, n + 1, &ps);
 
92
          if (__builtin_expect (n == (size_t) -1, 0))
 
93
-           /* Something wrong.
 
94
-              XXX Do we have to set `errno' to something which mbsrtows hasn't
 
95
-              already done?  */
 
96
-           return -1;
 
97
+           {
 
98
+             /* Something wrong.
 
99
+                XXX Do we have to set `errno' to something which
 
100
+                mbsrtows hasn't already done?  */
 
101
+           free_return:
 
102
+             free (wpattern_malloc);
 
103
+             return -1;
 
104
+           }
 
105
          if (p)
 
106
            {
 
107
              memset (&ps, '\0', sizeof (ps));
 
108
@@ -404,19 +422,32 @@ fnmatch (pattern, string, flags)
 
109
            /* Something wrong.
 
110
               XXX Do we have to set `errno' to something which mbsrtows hasn't
 
111
               already done?  */
 
112
-           return -1;
 
113
-         wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
 
114
+           goto free_return;
 
115
+
 
116
+         wstring_malloc = wstring
 
117
+           = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t));
 
118
+         if (wstring == NULL)
 
119
+           {
 
120
+             free (wpattern_malloc);
 
121
+             return -2;
 
122
+           }
 
123
          assert (mbsinit (&ps));
 
124
          (void) mbsrtowcs (wstring, &string, n + 1, &ps);
 
125
        }
 
126
 
 
127
-      return internal_fnwmatch (wpattern, wstring, wstring + n,
 
128
-                               flags & FNM_PERIOD, flags, NULL);
 
129
+      int res = internal_fnwmatch (wpattern, wstring, wstring + n,
 
130
+                                  flags & FNM_PERIOD, flags, NULL,
 
131
+                                  alloca_used);
 
132
+
 
133
+      free (wstring_malloc);
 
134
+      free (wpattern_malloc);
 
135
+
 
136
+      return res;
 
137
     }
 
138
 # endif  /* mbstate_t and mbsrtowcs or _LIBC.  */
 
139
 
 
140
   return internal_fnmatch (pattern, string, string + strlen (string),
 
141
-                          flags & FNM_PERIOD, flags, NULL);
 
142
+                          flags & FNM_PERIOD, flags, NULL, 0);
 
143
 }
 
144
 
 
145
 # ifdef _LIBC
 
146
Index: b/posix/fnmatch_loop.c
 
147
===================================================================
 
148
--- a/posix/fnmatch_loop.c
 
149
+++ b/posix/fnmatch_loop.c
 
150
@@ -1,4 +1,4 @@
 
151
-/* Copyright (C) 1991-1993,1996-2001,2003-2005,2007
 
152
+/* Copyright (C) 1991-1993,1996-2001,2003-2005,2007,2010
 
153
    Free Software Foundation, Inc.
 
154
    This file is part of the GNU C Library.
 
155
 
 
156
@@ -30,22 +30,24 @@ struct STRUCT
 
157
    it matches, nonzero if not.  */
 
158
 static int FCT (const CHAR *pattern, const CHAR *string,
 
159
                const CHAR *string_end, int no_leading_period, int flags,
 
160
-               struct STRUCT *ends)
 
161
+               struct STRUCT *ends, size_t alloca_used)
 
162
      internal_function;
 
163
 static int EXT (INT opt, const CHAR *pattern, const CHAR *string,
 
164
-               const CHAR *string_end, int no_leading_period, int flags)
 
165
+               const CHAR *string_end, int no_leading_period, int flags,
 
166
+               size_t alloca_used)
 
167
      internal_function;
 
168
 static const CHAR *END (const CHAR *patternp) internal_function;
 
169
 
 
170
 static int
 
171
 internal_function
 
172
-FCT (pattern, string, string_end, no_leading_period, flags, ends)
 
173
+FCT (pattern, string, string_end, no_leading_period, flags, ends, alloca_used)
 
174
      const CHAR *pattern;
 
175
      const CHAR *string;
 
176
      const CHAR *string_end;
 
177
      int no_leading_period;
 
178
      int flags;
 
179
      struct STRUCT *ends;
 
180
+     size_t alloca_used;
 
181
 {
 
182
   register const CHAR *p = pattern, *n = string;
 
183
   register UCHAR c;
 
184
@@ -74,10 +76,8 @@ FCT (pattern, string, string_end, no_lea
 
185
        case L('?'):
 
186
          if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
 
187
            {
 
188
-             int res;
 
189
-
 
190
-             res = EXT (c, p, n, string_end, no_leading_period,
 
191
-                        flags);
 
192
+             int res = EXT (c, p, n, string_end, no_leading_period,
 
193
+                            flags, alloca_used);
 
194
              if (res != -1)
 
195
                return res;
 
196
            }
 
197
@@ -106,10 +106,8 @@ FCT (pattern, string, string_end, no_lea
 
198
        case L('*'):
 
199
          if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
 
200
            {
 
201
-             int res;
 
202
-
 
203
-             res = EXT (c, p, n, string_end, no_leading_period,
 
204
-                        flags);
 
205
+             int res = EXT (c, p, n, string_end, no_leading_period,
 
206
+                            flags, alloca_used);
 
207
              if (res != -1)
 
208
                return res;
 
209
            }
 
210
@@ -198,7 +196,7 @@ FCT (pattern, string, string_end, no_lea
 
211
 
 
212
                  for (--p; n < endp; ++n, no_leading_period = 0)
 
213
                    if (FCT (p, n, string_end, no_leading_period, flags2,
 
214
-                            &end) == 0)
 
215
+                            &end, alloca_used) == 0)
 
216
                      goto found;
 
217
                }
 
218
              else if (c == L('/') && (flags & FNM_FILE_NAME))
 
219
@@ -207,7 +205,7 @@ FCT (pattern, string, string_end, no_lea
 
220
                    ++n;
 
221
                  if (n < string_end && *n == L('/')
 
222
                      && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags,
 
223
-                              NULL) == 0))
 
224
+                              NULL, alloca_used) == 0))
 
225
                    return 0;
 
226
                }
 
227
              else
 
228
@@ -221,7 +219,7 @@ FCT (pattern, string, string_end, no_lea
 
229
                  for (--p; n < endp; ++n, no_leading_period = 0)
 
230
                    if (FOLD ((UCHAR) *n) == c
 
231
                        && (FCT (p, n, string_end, no_leading_period, flags2,
 
232
-                                &end) == 0))
 
233
+                                &end, alloca_used) == 0))
 
234
                      {
 
235
                      found:
 
236
                        if (end.pattern == NULL)
 
237
@@ -758,7 +756,7 @@ FCT (pattern, string, string_end, no_lea
 
238
                                               _NL_COLLATE_SYMB_EXTRAMB);
 
239
 
 
240
                                /* Locate the character in the hashing
 
241
-                                   table.  */
 
242
+                                  table.  */
 
243
                                hash = elem_hash (str, c1);
 
244
 
 
245
                                idx = 0;
 
246
@@ -980,9 +978,8 @@ FCT (pattern, string, string_end, no_lea
 
247
        case L('!'):
 
248
          if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
 
249
            {
 
250
-             int res;
 
251
-
 
252
-             res = EXT (c, p, n, string_end, no_leading_period, flags);
 
253
+             int res = EXT (c, p, n, string_end, no_leading_period, flags,
 
254
+                            alloca_used);
 
255
              if (res != -1)
 
256
                return res;
 
257
            }
 
258
@@ -1061,26 +1058,32 @@ END (const CHAR *pattern)
 
259
 static int
 
260
 internal_function
 
261
 EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
 
262
-     int no_leading_period, int flags)
 
263
+     int no_leading_period, int flags, size_t alloca_used)
 
264
 {
 
265
   const CHAR *startp;
 
266
   int level;
 
267
   struct patternlist
 
268
   {
 
269
     struct patternlist *next;
 
270
+    CHAR malloced;
 
271
     CHAR str[0];
 
272
   } *list = NULL;
 
273
   struct patternlist **lastp = &list;
 
274
   size_t pattern_len = STRLEN (pattern);
 
275
+  int any_malloced = 0;
 
276
   const CHAR *p;
 
277
   const CHAR *rs;
 
278
+  int retval = 0;
 
279
 
 
280
   /* Parse the pattern.  Store the individual parts in the list.  */
 
281
   level = 0;
 
282
   for (startp = p = pattern + 1; level >= 0; ++p)
 
283
     if (*p == L('\0'))
 
284
-      /* This is an invalid pattern.  */
 
285
-      return -1;
 
286
+      {
 
287
+       /* This is an invalid pattern.  */
 
288
+       retval = -1;
 
289
+       goto out;
 
290
+      }
 
291
     else if (*p == L('['))
 
292
       {
 
293
        /* Handle brackets special.  */
 
294
@@ -1097,8 +1100,11 @@ EXT (INT opt, const CHAR *pattern, const
 
295
        /* Skip over all characters of the list.  */
 
296
        while (*p != L(']'))
 
297
          if (*p++ == L('\0'))
 
298
-           /* This is no valid pattern.  */
 
299
-           return -1;
 
300
+           {
 
301
+             /* This is no valid pattern.  */
 
302
+             retval = -1;
 
303
+             goto out;
 
304
+           }
 
305
       }
 
306
     else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
 
307
              || *p == L('!')) && p[1] == L('('))
 
308
@@ -1111,15 +1117,27 @@ EXT (INT opt, const CHAR *pattern, const
 
309
            /* This means we found the end of the pattern.  */
 
310
 #define NEW_PATTERN \
 
311
            struct patternlist *newp;                                         \
 
312
-                                                                             \
 
313
-           if (opt == L('?') || opt == L('@'))                               \
 
314
-             newp = alloca (sizeof (struct patternlist)                      \
 
315
-                            + (pattern_len * sizeof (CHAR)));                \
 
316
+           size_t slen = (opt == L('?') || opt == L('@')                     \
 
317
+                          ? pattern_len : (p - startp + 1));                 \
 
318
+           slen = sizeof (struct patternlist) + (slen * sizeof (CHAR));      \
 
319
+           int malloced = ! __libc_use_alloca (alloca_used + slen);          \
 
320
+           if (__builtin_expect (malloced, 0))                               \
 
321
+             {                                                               \
 
322
+               newp = alloca_account (slen, alloca_used);                    \
 
323
+               any_malloced = 1;                                             \
 
324
+             }                                                               \
 
325
            else                                                              \
 
326
-             newp = alloca (sizeof (struct patternlist)                      \
 
327
-                            + ((p - startp + 1) * sizeof (CHAR)));           \
 
328
-           *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0');    \
 
329
+             {                                                               \
 
330
+               newp = malloc (slen);                                         \
 
331
+               if (newp == NULL)                                             \
 
332
+                 {                                                           \
 
333
+                   retval = -2;                                              \
 
334
+                   goto out;                                                 \
 
335
+                 }                                                           \
 
336
+             }                                                               \
 
337
            newp->next = NULL;                                                \
 
338
+           newp->malloced = malloced;                                        \
 
339
+           *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0');    \
 
340
            *lastp = newp;                                                    \
 
341
            lastp = &newp->next
 
342
            NEW_PATTERN;
 
343
@@ -1140,8 +1158,9 @@ EXT (INT opt, const CHAR *pattern, const
 
344
   switch (opt)
 
345
     {
 
346
     case L('*'):
 
347
-      if (FCT (p, string, string_end, no_leading_period, flags, NULL) == 0)
 
348
-       return 0;
 
349
+      if (FCT (p, string, string_end, no_leading_period, flags, NULL,
 
350
+              alloca_used) == 0)
 
351
+       goto success;
 
352
       /* FALLTHROUGH */
 
353
 
 
354
     case L('+'):
 
355
@@ -1152,7 +1171,7 @@ EXT (INT opt, const CHAR *pattern, const
 
356
               current pattern.  */
 
357
            if (FCT (list->str, string, rs, no_leading_period,
 
358
                     flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
 
359
-                    NULL) == 0
 
360
+                    NULL, alloca_used) == 0
 
361
                /* This was successful.  Now match the rest with the rest
 
362
                   of the pattern.  */
 
363
                && (FCT (p, rs, string_end,
 
364
@@ -1160,7 +1179,7 @@ EXT (INT opt, const CHAR *pattern, const
 
365
                         ? no_leading_period
 
366
                         : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
 
367
                         flags & FNM_FILE_NAME
 
368
-                        ? flags : flags & ~FNM_PERIOD, NULL) == 0
 
369
+                        ? flags : flags & ~FNM_PERIOD, NULL, alloca_used) == 0
 
370
                    /* This didn't work.  Try the whole pattern.  */
 
371
                    || (rs != string
 
372
                        && FCT (pattern - 1, rs, string_end,
 
373
@@ -1169,18 +1188,21 @@ EXT (INT opt, const CHAR *pattern, const
 
374
                                : (rs[-1] == '/' && NO_LEADING_PERIOD (flags)
 
375
                                   ? 1 : 0),
 
376
                                flags & FNM_FILE_NAME
 
377
-                               ? flags : flags & ~FNM_PERIOD, NULL) == 0)))
 
378
+                               ? flags : flags & ~FNM_PERIOD, NULL,
 
379
+                               alloca_used) == 0)))
 
380
              /* It worked.  Signal success.  */
 
381
-             return 0;
 
382
+             goto success;
 
383
        }
 
384
       while ((list = list->next) != NULL);
 
385
 
 
386
       /* None of the patterns lead to a match.  */
 
387
-      return FNM_NOMATCH;
 
388
+      retval = FNM_NOMATCH;
 
389
+      break;
 
390
 
 
391
     case L('?'):
 
392
-      if (FCT (p, string, string_end, no_leading_period, flags, NULL) == 0)
 
393
-       return 0;
 
394
+      if (FCT (p, string, string_end, no_leading_period, flags, NULL,
 
395
+              alloca_used) == 0)
 
396
+       goto success;
 
397
       /* FALLTHROUGH */
 
398
 
 
399
     case L('@'):
 
400
@@ -1192,13 +1214,14 @@ EXT (INT opt, const CHAR *pattern, const
 
401
        if (FCT (STRCAT (list->str, p), string, string_end,
 
402
                 no_leading_period,
 
403
                 flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
 
404
-                NULL) == 0)
 
405
+                NULL, alloca_used) == 0)
 
406
          /* It worked.  Signal success.  */
 
407
-         return 0;
 
408
+         goto success;
 
409
       while ((list = list->next) != NULL);
 
410
 
 
411
       /* None of the patterns lead to a match.  */
 
412
-      return FNM_NOMATCH;
 
413
+      retval = FNM_NOMATCH;
 
414
+      break;
 
415
 
 
416
     case L('!'):
 
417
       for (rs = string; rs <= string_end; ++rs)
 
418
@@ -1208,7 +1231,7 @@ EXT (INT opt, const CHAR *pattern, const
 
419
          for (runp = list; runp != NULL; runp = runp->next)
 
420
            if (FCT (runp->str, string, rs,  no_leading_period,
 
421
                     flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
 
422
-                    NULL) == 0)
 
423
+                    NULL, alloca_used) == 0)
 
424
              break;
 
425
 
 
426
          /* If none of the patterns matched see whether the rest does.  */
 
427
@@ -1218,21 +1241,34 @@ EXT (INT opt, const CHAR *pattern, const
 
428
                       ? no_leading_period
 
429
                       : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
 
430
                       flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
 
431
-                      NULL) == 0))
 
432
+                      NULL, alloca_used) == 0))
 
433
            /* This is successful.  */
 
434
-           return 0;
 
435
+           goto success;
 
436
        }
 
437
 
 
438
       /* None of the patterns together with the rest of the pattern
 
439
         lead to a match.  */
 
440
-      return FNM_NOMATCH;
 
441
+      retval = FNM_NOMATCH;
 
442
+      break;
 
443
 
 
444
     default:
 
445
       assert (! "Invalid extended matching operator");
 
446
+      retval = -1;
 
447
       break;
 
448
     }
 
449
 
 
450
-  return -1;
 
451
+ success:
 
452
+ out:
 
453
+  if (any_malloced)
 
454
+    while (list != NULL)
 
455
+      {
 
456
+       struct patternlist *old = list;
 
457
+       list = list->next;
 
458
+       if (old->malloced)
 
459
+         free (old);
 
460
+      }
 
461
+
 
462
+  return retval;
 
463
 }
 
464
 
 
465