如何用更大的 char 指针列表覆盖 char 指针数组?

发布于 2024-08-25 07:01:48 字数 1693 浏览 16 评论 0原文

我的函数正在传递一个结构体,其中包含一个以 NULL 结尾的指针数组,这些指针指向组成带有参数的命令的单词。

我正在对参数列表执行全局匹配,将它们扩展为完整的文件列表,然后我想用新扩展的参数数组替换传递的参数数组。

通配工作正常,即 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:使用 Alok 的提示编辑内存管理
编辑 4:来自 alok 的更多提示
编辑5:几乎可以工作..应用程序在释放命令结构时出现段错误

最后:似乎我错过了终止NULL,所以添加行:

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

似乎使它工作。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

混吃等死 2024-09-01 07:01:48

argvchar * 的指针数组。这意味着 argv 有空间容纳 argc char * 值。如果您尝试将多个 char * 值复制到其中,最终会出现溢出。

您的 glob 调用很可能会在 gl_pathv 字段中产生多个 argc 元素(即 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_offssizeof *paths 字节。)
  4. 用于复制字符串的 for 循环应为 (j=1; j < g.gl_pathc + g.gl_offs; ++j)。
  5. 确保防止 shell 扩展您的全局。即,调用 ./a.out '*' 而不是 ./a.out *

argv is an array of pointers of char *. This means that argv has space for argc char * values. If you try to copy more than that many char * values into it, you will end up with an overflow.

Most likely your glob call results in more than argc elements in gl_pathv field (i.e, gl_pathc > argc). This is undefined behavior.

It is similar to the code below:

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

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

Solution: you should either work with the glob_t struct directly, or allocate new space to copy gl_pathv to a new 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 */

Edit: after your edit:

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

it should work, but each of argv[1] to argv[g.gl_pathc + g.gl_offs - 1] is a char * that is "owned" by the struct glob. Your memcpy call is only copying the pointers. When you later do globfree(), those pointers don't mean anything anymore. So, you need to do copy the strings for your use:

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]);

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.

  1. You are doing *p++, you should do p++, since you're not using the value of the dereferencing.
  2. You should really check the return value of glob.
  3. Your paths variable needs g.gl_pathc + 1 elements, not g.gl_pathc. (Or more correctly, you need to allocate g.gl_pathc + g.gl_offs times sizeof *paths bytes.)
  4. Your for loop to copy strings should be for (j=1; j < g.gl_pathc + g.gl_offs; ++j).
  5. Make sure you prevent shell from expanding your glob. I.e., call ./a.out '*' instead of ./a.out *.
并安 2024-09-01 07:01:48

您不需要将 g.gl_pathc 乘以 sizeof(char *) 吗?

Don't you need to multiple g.gl_pathc by sizeof(char *)?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文