ecore_file - fix nasty memory issues in ecore_file_app_exe_get()

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
This commit is contained in:
Carsten Haitzler 2015-04-01 09:30:13 +09:00
parent abf3c3c470
commit 4e716fb779
1 changed files with 40 additions and 125 deletions

View 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)
const char *home = getenv("HOME");
if (home) eina_strbuf_append(buf, home);
p++;
}
for (; *p; p++)
{
if (in_qout_double)
{
if (*p == '\'')
in_quot_sing = 0;
if (*p == '\\')
{
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 if (in_quot_dbl)
else if (in_qout_single)
{
if (*p == '\"')
in_quot_dbl = 0;
if (*p == '\\')
{
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
{
if (*p == '\'')
in_quot_sing = 1;
else if (*p == '\"')
in_quot_dbl = 1;
if ((isspace((unsigned char)*p)) && ((p <= app) || (p[-1] == '\\')))
break;
}
p++;
}
exe2 = p;
if (exe2 == exe1) return NULL;
if (*exe1 == '~')
{
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)
{
strcpy(exe, homedir);
pp += len;
if (*(pp - 1) != '/')
if (*p == '\\')
{
*pp = '/';
pp++;
if (p[1]) p++;
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)
{
if (*p == '\'')
in_quot_sing = 0;
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);
}
}
else if (in_quot_dbl)
{
if (*p == '\"')
in_quot_dbl = 0;
else
{
/* technically this is wrong. double quotes also accept
* special chars:
*
* $, `, \
*/
*pp = *p;
pp++;
}
}
else
{
/* technically we should handle special chars:
*
* $, `, \, etc.
*/
if ((p > exe1) && (p[-1] == '\\'))
{
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;
}
else
{
*pp = *p;
pp++;
}
}
p++;
}
*pp = 0;
exe = eina_strbuf_string_steal(buf);
eina_strbuf_free(buf);
return exe;
}