ecore_file - fix nasty memory issues in ecore_file_app_exe_get()
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Wed, 1 Apr 2015 00:30:13 +0000 (09:30 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Wed, 1 Apr 2015 00:37:27 +0000 (09:37 +0900)
valgrind was most unhappy with ecore_file_app_exe_get(). like:

==8331== Invalid write of size 1
==8331==    at 0x68DE90A: ecore_file_app_exe_get (ecore_file.c:994)
==8331==  Address 0x1348e58f is 0 bytes after a block of size 31 alloc'd
==8331==    at 0x4C28C20: malloc (vg_replace_malloc.c:296)
==8331== Invalid write of size 1
==8331==    at 0x68DE948: ecore_file_app_exe_get (ecore_file.c:1000)
==8331==  Address 0x1348e599 is 10 bytes after a block of size 31 alloc'd
==8331==    at 0x4C28C20: malloc (vg_replace_malloc.c:296)

etc. etc. - so i rewrote it cleanly using strbuf to save code and
effort. cleaner now and ACTUALLY works correctly... and no valgrind
complaints.

@fix

src/lib/ecore_file/ecore_file.c

index 372af03..dc105db 100644 (file)
@@ -857,147 +857,62 @@ ecore_file_ls(const char *dir)
 EAPI char *
 ecore_file_app_exe_get(const char *app)
 {
-   char *p, *pp, *exe1 = NULL, *exe2 = NULL;
-   char *exe = NULL;
-   int in_quot_dbl = 0, in_quot_sing = 0, restart = 0;
+   Eina_Strbuf *buf;
+   char *exe;
+   const char *p;
+   Eina_Bool in_qout_double = EINA_FALSE;
+   Eina_Bool in_qout_single = EINA_FALSE;
 
    if (!app) return NULL;
-
-   p = (char *)app;
-restart:
-   while ((*p) && (isspace((unsigned char)*p))) p++;
-   exe1 = p;
-   while (*p)
+   buf = eina_strbuf_new();
+   if (!buf) return NULL;
+   p = app;
+   if ((p[0] == '~') && (p[1] == '/'))
      {
-        if (in_quot_sing)
-          {
-             if (*p == '\'')
-               in_quot_sing = 0;
-          }
-        else if (in_quot_dbl)
-          {
-             if (*p == '\"')
-               in_quot_dbl = 0;
-          }
-        else
-          {
-             if (*p == '\'')
-               in_quot_sing = 1;
-             else if (*p == '\"')
-               in_quot_dbl = 1;
-             if ((isspace((unsigned char)*p)) && ((p <= app) || (p[-1] == '\\')))
-               break;
-          }
+        const char *home = getenv("HOME");
+        if (home) eina_strbuf_append(buf, home);
         p++;
      }
-   exe2 = p;
-   if (exe2 == exe1) return NULL;
-   if (*exe1 == '~')
+   for (; *p; p++)
      {
-        char *homedir;
-        int len;
-
-        /* Skip ~ */
-        exe1++;
-
-        homedir = getenv("HOME");
-        if (!homedir) return NULL;
-        len = strlen(homedir);
-        exe = malloc(len + exe2 - exe1 + 2);
-        if (!exe) return NULL;
-        pp = exe;
-        if (len)
+        if (in_qout_double)
           {
-             strcpy(exe, homedir);
-             pp += len;
-             if (*(pp - 1) != '/')
+             if (*p == '\\')
                {
-                  *pp = '/';
-                  pp++;
+                  if (p[1]) p++;
+                  eina_strbuf_append_char(buf, *p);
                }
+             else if (*p == '"') in_qout_double = EINA_FALSE;
+             else eina_strbuf_append_char(buf, *p);
           }
-     }
-   else
-     {
-        exe = malloc(exe2 - exe1 + 1);
-        if (!exe) return NULL;
-        pp = exe;
-     }
-   p = exe1;
-   restart = 0;
-   in_quot_dbl = 0;
-   in_quot_sing = 0;
-   while (*p)
-     {
-        if (in_quot_sing)
+        else if (in_qout_single)
           {
-             if (*p == '\'')
-               in_quot_sing = 0;
-             else
-               {
-                  *pp = *p;
-                  pp++;
-               }
-          }
-        else if (in_quot_dbl)
-          {
-             if (*p == '\"')
-               in_quot_dbl = 0;
-             else
+             if (*p == '\\')
                {
-                  /* technically this is wrong. double quotes also accept
-                   * special chars:
-                   *
-                   * $, `, \
-                   */
-                  *pp = *p;
-                  pp++;
+                  if (p[1]) p++;
+                  eina_strbuf_append_char(buf, *p);
                }
+             else if (*p == '\'') in_qout_single = EINA_FALSE;
+             else eina_strbuf_append_char(buf, *p);
           }
         else
           {
-             /* technically we should handle special chars:
-              *
-              * $, `, \, etc.
-              */
-             if ((p > exe1) && (p[-1] == '\\'))
+             if (*p == '\\')
                {
-                  if (*p != '\n')
-                    {
-                       *pp = *p;
-                       pp++;
-                    }
-               }
-             else if ((p > exe1) && (*p == '='))
-               {
-                  restart = 1;
-                  *pp = *p;
-                  pp++;
-               }
-             else if (*p == '\'')
-               in_quot_sing = 1;
-             else if (*p == '\"')
-               in_quot_dbl = 1;
-             else if (isspace((unsigned char)*p))
-               {
-                  if (restart)
-                    {
-                       if (exe) free(exe);
-                       exe = NULL;
-                       goto restart;
-                    }
-                  else
-                    break;
+                  if (p[1]) p++;
+                  eina_strbuf_append_char(buf, *p);
                }
+             else if (*p == '"') in_qout_double = EINA_TRUE;
+             else if (*p == '\'') in_qout_single = EINA_TRUE;
              else
                {
-                  *pp = *p;
-                  pp++;
+                  if (isspace((unsigned char)(*p))) break;
+                  eina_strbuf_append_char(buf, *p);
                }
           }
-        p++;
      }
-   *pp = 0;
+   exe = eina_strbuf_string_steal(buf);
+   eina_strbuf_free(buf);
    return exe;
 }