My function is being passed a struct containing, among other things, a NULL terminated array of pointers to words making up a command with arguments.
I’m performing a glob match on the list of arguments, to expand them into a full list of files, then I want to replace the passed argument array with the new expanded one.
The globbing is working fine, that is, g.gl_pathv is populated with the list of expected files. However, I am having trouble copying this array into the struct I was given.
#include <glob.h>
struct command {
char **argv;
// other fields...
}
void myFunction( struct command * cmd )
{
char **p = cmd->argv;
char* program = *p++; // save the program name (e.g 'ls', and increment to the first argument
glob_t g;
memset(&g, 0, sizeof(g));
g.gl_offs = 1;
int res = glob(*p++, GLOB_DOOFFS, NULL, &g);
glob_handle_res(res);
while (*p)
{
res = glob(*p, GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
glob_handle_res(res);
}
if( g.gl_pathc <= 0 )
{
globfree(&g);
}
cmd->argv = malloc((g.gl_pathc + g.gl_offs) * sizeof *cmd->argv);
if (cmd->argv == NULL) { sys_fatal_error("pattern_expand: malloc failed\n");}
// copy over the arguments
size_t i = g.gl_offs;
for (; i < g.gl_pathc + g.gl_offs; ++i)
cmd->argv[i] = strdup(g.gl_pathv[i]);
// insert the original program name
cmd->argv[0] = strdup(program);
** cmd->argv[g.gl_pathc + g.gl_offs] = 0; **
globfree(&g);
}
void
command_free(struct esh_command * cmd)
{
char ** p = cmd->argv;
while (*p) {
free(*p++); // Segfaults here, was it already freed?
}
free(cmd->argv);
free(cmd);
}
Edit 1: Also, I realized I need to stick program back in there as cmd->argv[0]
Edit 2: Added call to calloc
Edit 3: Edit mem management with tips from Alok
Edit 4: More tips from alok
Edit 5: Almost working.. the app segfaults when freeing the command struct
Finally: Seems like I was missing the terminating NULL, so adding the line:
cmd->argv[g.gl_pathc + g.gl_offs] = 0;
seemed to make it work.
argvis an array of pointers ofchar *. This means thatargvhas space forargcchar *values. If you try to copy more than that manychar *values into it, you will end up with an overflow.Most likely your
globcall results in more thanargcelements ingl_pathvfield (i.e,gl_pathc > argc). This is undefined behavior.It is similar to the code below:
Solution: you should either work with the
glob_tstruct directly, or allocate new space to copygl_pathvto a newchar **:Edit: after your edit:
it should work, but each of
argv[1]toargv[g.gl_pathc + g.gl_offs - 1]is achar *that is “owned” by thestruct glob. Yourmemcpycall is only copying the pointers. When you later doglobfree(), those pointers don’t mean anything anymore. So, you need to do copy the strings for your use:This makes sure you now have your own private copies of the strings. Be sure to free them (and
argv) once you are done.There are a few other problems with your code.
*p++, you should dop++, since you’re not using the value of the dereferencing.glob.pathsvariable needsg.gl_pathc + 1elements, notg.gl_pathc. (Or more correctly, you need to allocateg.gl_pathc + g.gl_offstimessizeof *pathsbytes.)forloop to copy strings should befor (j=1; j < g.gl_pathc + g.gl_offs; ++j)../a.out '*'instead of./a.out *.