bug-gnulib
[Top][All Lists]
Advanced

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

fnmatch memory allocation fix


From: Bruno Haible
Subject: fnmatch memory allocation fix
Date: Mon, 31 Jul 2006 16:44:23 +0200
User-agent: KMail/1.9.1

Hi,

When trying to use the 'fnmatch' module for GNU gettext, I found thst it
still depends on the old 'alloca' module that relies on an external function
on platforms like HP-UX 10.00 with cc. IMO the better choice is to use
the 'alloca-opt' module and hand-optimized code for modules that come from
glibc, and the 'allocsa' module for higher-level code.

Furthermore fnmatch_loop.c has a gratuitous limit of 2000 characters for
patterns; 2000 is less than PATH_MAX!

Here is a proposed patch to fix both.


2006-07-30  Bruno Haible  <address@hidden>

        * fnmatch.c (fnmatch): On platforms without alloca, set ALLOCA_LIMIT
        to 0, so that the memory allocation always uses malloc.
        * fnmatch_loop.c (EXT): Use malloc as alternative to alloca, when
        the pattern size is big. On platforms without alloca, set ALLOCA_LIMIT
        to 0, so that the memory allocation always uses malloc.
        * modules/fnmatch (Depends-on): Add alloca-opt, remove alloca.

*** lib/fnmatch.c.bak   2006-07-11 13:54:17.000000000 +0200
--- lib/fnmatch.c       2006-07-30 20:23:09.000000000 +0200
***************
*** 276,282 ****
  fnmatch (const char *pattern, const char *string, int flags)
  {
  # if HANDLE_MULTIBYTE
! #  define ALLOCA_LIMIT 2000
    if (__builtin_expect (MB_CUR_MAX, 1) != 1)
      {
        mbstate_t ps;
--- 276,286 ----
  fnmatch (const char *pattern, const char *string, int flags)
  {
  # if HANDLE_MULTIBYTE
! #  if HAVE_ALLOCA || defined _LIBC
! #   define ALLOCA_LIMIT 2000
! #  else
! #   define ALLOCA_LIMIT 0
! #  endif
    if (__builtin_expect (MB_CUR_MAX, 1) != 1)
      {
        mbstate_t ps;
*** lib/fnmatch_loop.c.bak      2006-07-11 13:54:17.000000000 +0200
--- lib/fnmatch_loop.c  2006-07-30 21:03:04.000000000 +0200
***************
*** 1003,1022 ****
    struct patternlist
    {
      struct patternlist *next;
      CHAR str[1];
    } *list = NULL;
    struct patternlist **lastp = &list;
    size_t pattern_len = STRLEN (pattern);
    const CHAR *p;
    const CHAR *rs;
    enum { ALLOCA_LIMIT = 8000 };
  
    /* Parse the pattern.  Store the individual parts in the list.  */
    level = 0;
    for (startp = p = pattern + 1; ; ++p)
      if (*p == L_('\0'))
        /* This is an invalid pattern.  */
!       return -1;
      else if (*p == L_('['))
        {
        /* Handle brackets special.  */
--- 1003,1028 ----
    struct patternlist
    {
      struct patternlist *next;
+     int malloced;
      CHAR str[1];
    } *list = NULL;
    struct patternlist **lastp = &list;
    size_t pattern_len = STRLEN (pattern);
    const CHAR *p;
    const CHAR *rs;
+ #if HAVE_ALLOCA || defined _LIBC
    enum { ALLOCA_LIMIT = 8000 };
+ #else
+   enum { ALLOCA_LIMIT = 0 };
+ #endif
+   int retval;
  
    /* Parse the pattern.  Store the individual parts in the list.  */
    level = 0;
    for (startp = p = pattern + 1; ; ++p)
      if (*p == L_('\0'))
        /* This is an invalid pattern.  */
!       goto failed;
      else if (*p == L_('['))
        {
        /* Handle brackets special.  */
***************
*** 1034,1040 ****
        while (*p != L_(']'))
          if (*p++ == L_('\0'))
            /* This is no valid pattern.  */
!           return -1;
        }
      else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@')
              || *p == L_('!')) && p[1] == L_('('))
--- 1040,1046 ----
        while (*p != L_(']'))
          if (*p++ == L_('\0'))
            /* This is no valid pattern.  */
!           goto failed;
        }
      else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@')
              || *p == L_('!')) && p[1] == L_('('))
***************
*** 1057,1067 ****
            plensize = plen * sizeof (CHAR);                                  \
            newpsize = offsetof (struct patternlist, str) + plensize;         \
            if ((size_t) -1 / sizeof (CHAR) < plen                            \
!               || newpsize < offsetof (struct patternlist, str)              \
!               || ALLOCA_LIMIT <= newpsize)                                  \
!             return -1;                                                      \
!           newp = (struct patternlist *) alloca (newpsize);                  \
!           *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0');    \
            newp->next = NULL;                                                \
            *lastp = newp;                                                    \
            lastp = &newp->next
--- 1063,1083 ----
            plensize = plen * sizeof (CHAR);                                  \
            newpsize = offsetof (struct patternlist, str) + plensize;         \
            if ((size_t) -1 / sizeof (CHAR) < plen                            \
!               || newpsize < offsetof (struct patternlist, str))             \
!             goto failed;                                                    \
!           if (newpsize < ALLOCA_LIMIT)                                      \
!             {                                                               \
!               newp = (struct patternlist *) alloca (newpsize);              \
!               newp->malloced = 0;                                           \
!             }                                                               \
!           else                                                              \
!             {                                                               \
!               newp = (struct patternlist *) malloc (newpsize);              \
!               if (!newp)                                                    \
!                 goto failed;                                                \
!               newp->malloced = 1;                                           \
!             }                                                               \
!           *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0');   \
            newp->next = NULL;                                                \
            *lastp = newp;                                                    \
            lastp = &newp->next
***************
*** 1085,1096 ****
      {
      case L_('*'):
        if (FCT (p, string, string_end, no_leading_period, flags) == 0)
!       return 0;
        /* FALLTHROUGH */
  
      case L_('+'):
        do
        {
          for (rs = string; rs <= string_end; ++rs)
            /* First match the prefix with the current pattern with the
               current pattern.  */
--- 1101,1117 ----
      {
      case L_('*'):
        if (FCT (p, string, string_end, no_leading_period, flags) == 0)
!       {
!         retval = 0;
!         goto done;
!       }
        /* FALLTHROUGH */
  
      case L_('+'):
        do
        {
+         struct patternlist *next;
+ 
          for (rs = string; rs <= string_end; ++rs)
            /* First match the prefix with the current pattern with the
               current pattern.  */
***************
*** 1112,1142 ****
                                : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
                                flags & FNM_FILE_NAME
                                ? flags : flags & ~FNM_PERIOD) == 0)))
!             /* It worked.  Signal success.  */
!             return 0;
        }
!       while ((list = list->next) != NULL);
  
        /* None of the patterns lead to a match.  */
        return FNM_NOMATCH;
  
      case L_('?'):
        if (FCT (p, string, string_end, no_leading_period, flags) == 0)
!       return 0;
        /* FALLTHROUGH */
  
      case L_('@'):
        do
!       /* I cannot believe it but `strcat' is actually acceptable
!          here.  Match the entire string with the prefix from the
!          pattern list and the rest of the pattern following the
!          pattern list.  */
!       if (FCT (STRCAT (list->str, p), string, string_end,
!                no_leading_period,
!                flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
!         /* It worked.  Signal success.  */
!         return 0;
!       while ((list = list->next) != NULL);
  
        /* None of the patterns lead to a match.  */
        return FNM_NOMATCH;
--- 1133,1186 ----
                                : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
                                flags & FNM_FILE_NAME
                                ? flags : flags & ~FNM_PERIOD) == 0)))
!             {
!               /* It worked.  Signal success.  */
!               retval = 0;
!               goto done;
!             }
! 
!         next = list->next;
!         if (list->malloced)
!           free (list);
!         list = next;
        }
!       while (list != NULL);
  
        /* None of the patterns lead to a match.  */
        return FNM_NOMATCH;
  
      case L_('?'):
        if (FCT (p, string, string_end, no_leading_period, flags) == 0)
!       {
!         retval = 0;
!         goto done;
!       }
        /* FALLTHROUGH */
  
      case L_('@'):
        do
!       {
!         struct patternlist *next;
! 
!         /* I cannot believe it but `strcat' is actually acceptable
!            here.  Match the entire string with the prefix from the
!            pattern list and the rest of the pattern following the
!            pattern list.  */
!         if (FCT (STRCAT (list->str, p), string, string_end,
!                  no_leading_period,
!                  flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
!           {
!             /* It worked.  Signal success.  */
!             retval = 0;
!             goto done;
!           }
! 
!         next = list->next;
!         if (list->malloced)
!           free (list);
!         list = next;
!       }
!       while (list != NULL);
  
        /* None of the patterns lead to a match.  */
        return FNM_NOMATCH;
***************
*** 1159,1178 ****
                       : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
                       flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD)
                  == 0))
!           /* This is successful.  */
!           return 0;
        }
  
        /* None of the patterns together with the rest of the pattern
         lead to a match.  */
!       return FNM_NOMATCH;
  
      default:
        assert (! "Invalid extended matching operator");
        break;
      }
  
!   return -1;
  }
  
  
--- 1203,1237 ----
                       : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
                       flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD)
                  == 0))
!           {
!             /* This is successful.  */
!             retval = 0;
!             goto done;
!           }
        }
  
        /* None of the patterns together with the rest of the pattern
         lead to a match.  */
!       retval = FNM_NOMATCH;
!       goto done;
  
      default:
        assert (! "Invalid extended matching operator");
        break;
      }
  
!  failed:
!   retval = -1;
!  done:
!   while (list != NULL)
!     {
!       struct patternlist *next = list->next;
! 
!       if (list->malloced)
!       free (list);
!       list = next;
!     }
!   return retval;
  }
  
  
*** modules/fnmatch.bak 2005-07-23 00:04:12.000000000 +0200
--- modules/fnmatch     2006-07-30 20:44:18.000000000 +0200
***************
*** 9,15 ****
  m4/fnmatch.m4
  
  Depends-on:
! alloca
  stdbool
  
  configure.ac:
--- 9,15 ----
  m4/fnmatch.m4
  
  Depends-on:
! alloca-opt
  stdbool
  
  configure.ac:




reply via email to

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