Как переписать массив указателей на символы с большим списком указателей на символы? - PullRequest
0 голосов
/ 15 марта 2010

Моей функции передается структура, содержащая, среди прочего, завершенный массив указателей на слова со словами, составляющими команду с аргументами.

Я выполняю сопоставление глобуса в списке аргументов, чтобы развернуть их в полный список файлов, затем я хочу заменить массив переданных аргументов новым расширенным.

Глобирование работает нормально, то есть g.gl_pathv заполняется списком ожидаемых файлов. Однако у меня возникают проблемы при копировании этого массива в структуру, которую мне дали.

#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);
}

Редактировать 1: Я также понял, что мне нужно вставить туда программу, как cmd-> argv [0]
Редактировать 2: Добавлен вызов в Calloc
Редактировать 3: Редактировать управление Mem с советами от Alok
Редактировать 4: Дополнительные советы от Alok
Редактировать 5: Почти работает .. Сегменты приложения сбрасываются при освобождении команды struct

Наконец: кажется, что я пропустил завершающий NULL, поэтому добавив строку:

cmd->argv[g.gl_pathc + g.gl_offs] = 0;  

казалось, заставил это работать.

Ответы [ 2 ]

1 голос
/ 15 марта 2010

argv - это массив указателей char *. Это означает, что argv имеет место для значений argc char *. Если вы попытаетесь скопировать в него больше, чем столько char * значений, вы получите переполнение.

Скорее всего, ваш glob вызов приведет к более чем argc элементам в поле gl_pathv (т.е. gl_pathc > argc). Это неопределенное поведение.

Это похоже на код ниже:

/* Wrong code */
#include <string.h>

int a[] = { 1, 2, 3 };
int b[] = { 1, 2, 3, 4 };
memcpy(a, b, sizeof b);

Решение: вы должны либо работать со структурой glob_t напрямую, либо выделять новое пространство для копирования gl_pathv в новый char **:

char **paths = malloc(g.gl_pathc * sizeof *paths);
if (paths == NULL) { /* handle error */ }
for (size_t i=0; i < g.gl_pathc; ++i) {
    /* The following just copies the pointer */
    paths[i] = g.gl_pathv[i];

    /* If you actually want to copy the string, then
       you need to malloc again here.

       Something like:

       paths[i] = malloc(strlen(g.gl_pathv[i] + 1));

       followed by strcpy.
     */
}

/* free all the allocated data when done */

Редактировать : после редактирования:

cmd->argv = calloc(g.gl_pathc, sizeof(char *) *g.gl_pathc);

это должно работать, но каждый из argv[1] - argv[g.gl_pathc + g.gl_offs - 1] - это char *, который "принадлежит" struct glob. Ваш memcpy звонок только копирует указатели. Когда вы позже делаете globfree(), эти указатели больше ничего не значат. Итак, вам нужно скопировать строки для вашего использования:

size_t i;
cmd->argv = malloc((g.gl_pathc+g.gl_offs) * sizeof *cmd->argv);
for (i=g.gl_offs; i < g.gl_pathc + g.gl_offs; ++i)
    cmd->argv[i] = strdup(g.gl_pathv[i]);

Это гарантирует, что теперь у вас есть свои собственные частные копии строк. Обязательно освободите их (и argv), как только вы закончите.

Есть несколько других проблем с вашим кодом.

  1. Вы делаете *p++, вы должны сделать p++, так как вы не используете значение разыменования.
  2. Вы действительно должны проверить возвращаемое значение glob.
  3. Ваша переменная paths нуждается в g.gl_pathc + 1 элементах, а не g.gl_pathc. (Точнее, вам нужно выделить g.gl_pathc + g.gl_offs раз sizeof *paths байт.)
  4. Ваш цикл for для копирования строк должен быть for (j=1; j < g.gl_pathc + g.gl_offs; ++j).
  5. Убедитесь, что оболочка не расширяет ваш шар. То есть звоните ./a.out '*' вместо ./a.out *.
0 голосов
/ 15 марта 2010

Вам не нужно умножить g.gl_pathc на sizeof (char *)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...