[AD] config.c memory leak/arbitrary limit

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


The attached patch, based on one made by Miran Amos, fixes an undocumented 
limit to the number of return values by get_config_argv. I also fixed a 
(very minor) memory leak while I was at it.

Evert
Index: src/config.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/config.c,v
retrieving revision 1.29
diff -u -r1.29 config.c
--- src/config.c	31 Mar 2005 20:16:24 -0000	1.29
+++ src/config.c	23 May 2005 16:44:43 -0000
@@ -62,6 +62,10 @@
 
 static int config_installed = FALSE;
 
+static char **config_argv = NULL;
+static char *argv_buf = NULL;
+static int argv_buf_size = 0;
+
 
 
 /* flush_config:
@@ -203,6 +207,14 @@
       config_hook = NULL;
    }
 
+   free(config_argv);
+   config_argv = NULL;
+   
+   free(argv_buf);
+   argv_buf = NULL;
+   
+   argv_buf_size = 0;
+
    _remove_exit_func(config_cleanup);
    config_installed = FALSE;
 }
@@ -904,13 +916,9 @@
  */
 char **get_config_argv(AL_CONST char *section, AL_CONST char *name, int *argc)
 {
-   #define MAX_ARGV  16
-
-   static char *buf = NULL;
-   static int buf_size = 0;
-   static char *argv[MAX_ARGV];
    int pos, ac, q, c;
    int s_size;
+   int i;
 
    AL_CONST char *s = get_config_string(section, name, NULL);
 
@@ -919,56 +927,97 @@
       return NULL;
    }
 
+   /* clean up the old argv that was allocated the last time this function was
+    * called.
+    */
+   free(config_argv);
+   config_argv = NULL;
+
    /* increase the buffer size if needed */
    s_size = ustrsizez(s);
-   if (s_size>buf_size) {
-      buf_size = s_size;
-      buf = _al_sane_realloc(buf, buf_size);
-      if (!buf) {
-	 *allegro_errno = ENOMEM;
-	 *argc = 0;
-	 return NULL;
+   if (s_size>argv_buf_size) {
+      argv_buf_size = s_size;
+      argv_buf = _al_sane_realloc(argv_buf, argv_buf_size);
+      if (!argv_buf) {
+         *allegro_errno = ENOMEM;
+         *argc = 0;
+         return NULL;
       }
    }
 
-   ustrzcpy(buf, buf_size, s);
+   ustrzcpy(argv_buf, argv_buf_size, s);
    pos = 0;
    ac = 0;
 
-   c = ugetc(buf);
-
-   while ((ac<MAX_ARGV) && (c) && (c != '#')) {
+   /* tokenize the buffer and count the number of words; every space character
+    * as well as single and double quotes are replaced with zeros; comments * that start with # are also cut off with a 0
+    */
+   c = ugetc(argv_buf);
+   while ((c) && (c != '#')) {
+      /* replace all spaces up to the next word with 0 */
       while ((c) && (uisspace(c))) {
-	 pos += ucwidth(c);
-	 c = ugetc(buf+pos);
+	 usetat(argv_buf+pos, 0, 0);
+	 pos += ucwidth(0);
+	 c = ugetc(argv_buf+pos);
       }
 
+      /* quit if we reached the end of the buffer or a comment */
       if ((c) && (c != '#')) {
-	 if ((c == '\'') || (c == '"')) {
-	    q = c;
-	    pos += ucwidth(c);
-	    c = ugetc(buf+pos);
-	 }
-	 else
-	    q = 0;
+         /* found another word! */
+         ac++;
 
-	 argv[ac++] = buf+pos;
+         /* cut away quotes by replacing them with 0 */
+         if ((c == '\'') || (c == '"')) {
+            q = c;
+            usetat(argv_buf+pos, 0, 0);
+            pos += ucwidth(0);
+            c = ugetc(argv_buf+pos);
+         }
+         else {
+            q = 0;
+         }
 
-	 while ((c) && ((q) ? (c != q) : (!uisspace(c)))) {
-	    pos += ucwidth(c);
-	    c = ugetc(buf+pos);
-	 }
+         /* search for the end of the word */
+         while ((c) && ((q) ? (c != q) : (!uisspace(c)))) {
+            pos += ucwidth(c);
+            c = ugetc(argv_buf+pos);
+         }
+      }
+   }
 
-	 if (c) {
-	    usetat(buf+pos, 0, 0);
-	    pos += ucwidth(0);
-	    c = ugetc(buf+pos);
-	 }
+   /* now that we know how many words there are in the buffer, allocate enough
+    * space for a list of pointers to them, or return 0 if there are no words
+    */
+   if (ac > 0) {
+      config_argv = malloc(ac*sizeof *config_argv);
+   }
+   else {
+      *argc = 0;
+      return NULL;
+   }
+
+   /* go through the tokenized buffer and assign pointers in argv to point to
+    * the beginning of each individual word
+    */
+   for (i=0,pos=0,c=ugetc(argv_buf); i<ac; i++) {
+      /* find next word */
+      while (!c) {
+         pos += ucwidth(c);
+         c = ugetc(argv_buf+pos);
+      }
+
+      /* assign pointer */
+      config_argv[i] = argv_buf+pos;
+
+      /* find end of the word */
+      while (c) {
+         pos += ucwidth(c);
+         c = ugetc(argv_buf+pos);
       }
    }
 
    *argc = ac;
-   return argv;
+   return config_argv;
 }
 
 


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/