【问题标题】:Create a safe nullpointer in regards to memory leaks针对内存泄漏创建一个安全的空指针
【发布时间】:2016-12-11 19:02:52
【问题描述】:

看看这个:

    char (*options)[MAXLEN];
    char *ptr;
    ptr = strtok(input, " \r\n");
    if(!ptr)
        continue;
    int i = 0;
    optionen = malloc(sizeof(*options));
    if(!options)
        die("malloc");
    while(ptr){
        if(i > 0){
            options = realloc(options, (i+1)*sizeof(*options));
            if(!options)
                die("malloc");
        }
        strcpy(options[i], ptr);
        if(!options[i])
            die("strcpy");
        ptr = strtok(NULL, " \r\n");
        i++;
    }


/*create another entry options[i] that is a nullpointer*/

目的是 exec(3) 命令需要一个空指针作为 *options[] 数组的最后一个条目才能正常工作。

问题:如何向数组中添加另一个 NULL 指针条目?我知道我无法分配另一个 options[i] 并将其设置为 NULL,因为 stackoverflow 上的某个人告诉我永远不要这样做(内存泄漏)。

注意:输入是一些包含一些命令行的数组 - 输入(char input[MAXLEN];)和die() 只是调用perror() 然后exit()

【问题讨论】:

  • 不要相信他们说的话。分配另一个条目并将其值设置为NULL
  • 你能给我一个例子行吗?
  • 我是否正确读取和解析char (*options)[MAXLEN]; 中的options 是指向MAXLEN 字符数组的指针?这是故意的吗?
  • 是的,这就是意图
  • Josch,如果你知道options[i] 是一个字符,你为什么还要这样做strcpy(options[i], ptr); ?你打开编译器警告了吗?

标签: c arrays null-pointer


【解决方案1】:

谁告诉你“不能分配另一个 options[i] 并将其设置为 NULL”是错误的。这正是你所做的。

但是,您的代码中存在错误,这些错误表明您不理解“分配另一个 options[i]”的含义

char (*options)[MAXLEN];  /* This is wrong */
char *ptr;
ptr = strtok(input, " \r\n");
if(!ptr)
    continue;
int i = 0;
optionen = malloc(sizeof(*options));
if(!options)
    die("malloc");
while(ptr){
    if(i > 0){
        options = realloc(options, (i+1)*sizeof(*options));
        if(!options)
            die("malloc");
    }
    strcpy(options[i], ptr); /* This is also wrong */
    if(!options[i])
        die("strcpy");
    ptr = strtok(NULL, " \r\n");
    i++;
}

首先,char (*options)[MAXLEN] 是错误类型的数组,其中的条目不能设置为 NULL。你需要char **options

其次,您已经在执行的realloc 操作实际上是分配更多options[i] 插槽。但是您需要为字符串本身分配空间(但为NULL)。你可以通过strdup 做到这一点。

options[i] = strdup(ptr); /* Instead of the "also wrong" line */

(取决于input 是什么,您可能只使用strtok 返回的字符串指针就可以侥幸逃脱,但如果没有看到更多代码,我无法确定这是安全的。)

然后,在循环之后,您只需将最终的 options[i] 插槽设置为 NULL 即可。

我会以不同的方式构造循环,如下所示:

char **options;
char *ptr;
size_t i, asize;

ptr = strtok(input, " \t\r\n");
if (!ptr) continue;

options = 0;
i = 0;
asize = 2;
do {
    while (i >= asize) {
        asize *= 2;
        options = xreallocarray(options, asize, sizeof(char *));
    }
    options[i++] = xstrdup(ptr);
    ptr = strtok(0, " \t\r\n");
} while (ptr);

while (i >= asize) {
    asize *= 2;
    options = xreallocarray(options, asize, sizeof(char *));
}
options[i] = 0;

execve(options[0], options, environ);
die("execve");

函数xreallocarrayxstrdup 是非标准的,但它们应该包含在您编写的每个程序中添加的简单函数包中。这是他们的定义。他们使用你已经拥有的 die() 函数。

void *
xreallocarray(void *optr, size_t nmemb, size_t size)
{
    /* s1*s2 <= SIZE_MAX if both s1 < K and s2 < K where K = sqrt(SIZE_MAX+1) */
    const size_t MUL_NO_OVERFLOW = ((size_t)1) << (sizeof(size_t) * 4);

    if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
        nmemb > 0 && SIZE_MAX / nmemb < size) {
        errno = ENOMEM;
        die("malloc");
    }

    void *rv = realloc(optr, size * nmemb);
    if (!rv)
        die("malloc");
    return rv;
}

char *
xstrdup(const char *s)
{
    size_t n = strlen(s) + 1;
    char *rv = malloc(n);
    if (!rv)
        die("malloc");
    memcpy(rv, s, n);
    return rv;
}

【讨论】:

  • Zwol,我强烈建议你使用realloc等标准函数,不要推送自己喜欢的函数。您的函数没有记录在案,也没有解释它们做什么或为什么需要它们,也不解释它们是为哪个平台编写的。
【解决方案2】:

我的建议:如下创建另一个数组,并在对exec 的调用中使用它。

char** args = malloc((i+1)*sizeof(*args));
for (int j = 0; j < i; ++j )
{
   args[j] = options[j];
}
args[i] = NULL;

execvp(..., args);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-18
    • 2014-08-25
    • 2013-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-31
    相关资源
    最近更新 更多