valgrind条件跳转或移动取决于未初始化

时间:2020-05-11 11:33:10

标签: c valgrind

Valgrind对两行代码抛出两个警告,每一行旁边的注释中都提到了。

警告1

大小为8的无效写入,地址...在大小为一个块的内部为8个字节 9已分配

data[size] = NULL;

警告2

有条件的跳跃或移动取决于未初始化的值

for (char **ptr = data; *ptr; ptr++) { // warning -> Conditional jump or move depends on uninitialized values(s)
    free(*ptr);
}

这是完整的代码,

被叫方

char **getList() {
    char **list = (char *[]) {"John", "Jane", NULL};

    int size = 0;
    for (char **ptr = list; *ptr; ptr++) {
        size++;
    }

    char **data = malloc(sizeof(char *) * size + 1);
    if (data == NULL) goto exception;

    for (int i = 0; *list; list++, i++) {
        data[i] = malloc(sizeof(char) * (strlen(*list) + 1));
        if (data[i] == NULL) goto exception;
        strcpy(data[i], *list);
    }

    data[size] = NULL; // this line gives warning
    // warning -> invalid write of size 8, Address ... is 8 bytes inside a block of size 9 alloc'd
    return data;

    exception:
    fprintf(stderr, "data allocation failed.\n");
    return NULL;
}

呼叫者不同的文件/范围

char **data = getList();

for (char **ptr = data; *ptr; ptr++) { // warning -> Conditional jump or move depends on uninitialized values(s)
    free(*ptr);
}
free(data);

2 个答案:

答案 0 :(得分:1)

根据新的建议撰写。

编辑已根据评论进行了更新。

char **getList(void) {
    const char * const list[] = {"John", "Jane", NULL};

    unsigned int size = 0;
    const char * const *ptr;
    for (ptr = list; *ptr != NULL; ptr++) {
        size++;
    }

    char **data = malloc(sizeof(char *) * (size + 1));
    if (data == NULL) goto exception;

    ptr = list;
    for (unsigned int i = 0; *ptr != NULL; ptr++, i++) {
        const size_t cache = strlen(*ptr) + 1;
        data[i] = malloc(cache);
        if (data[i] == NULL) goto exception;
        memcpy(data[i], *ptr, cache);
    }

    data[size] = NULL;
    return data;

    exception:
    fprintf(stderr, "Allocation failed.\n");
    return NULL;
}

版本2

借助azure.datafactory.tools

const char * const *getList(void) {
    static const char * const list[] = {"John", "Jane", NULL};
    return list;
}

答案 1 :(得分:0)

以下代码未经测试。我的建议是

  • 使用strdup
  • 使用calloc
  • 尝试避免使用goto

    char ** getList(){ char ** list =(char * []){“ John”,“ Jane”,NULL};

    // this size is a compile time constant, no need to
    calculate it at runtime
    size_t size = sizeof(list)/sizeof(list[0]);
    
    // using calloc initializes everything to 0/NULL
    // -> no need to set the last element then
    char **data = calloc(sizeof(char *), size);
    
    // don't use goto
    if (data != NULL)
    {
        for (size_t i = 0U; i < size; i++)
        {
            if (list[i] != NULL)
            {
                // don't re-invent the wheel with strlen/memcpy
                // just use strdup
                data[i] = strdup(list[i]);
                if (data[i] == NULL) goto exception;
            }
        }
        return data;
    }
    
    exception:
    // you need to do more cleanup here
    // for instance if the 'data' calloc succeeds, the "John" strdup succeeds
    // but the "Jane" strdup fails then you have two leaks. That said fixing
    // small leaks when you are out of memory usually isn't your biggest issue.
    fprintf(stderr, "data allocation failed.\n");
    return NULL;
    

    }