首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GCC (主干) -fanalyzer [CWE-401]假阳性?

GCC (主干) -fanalyzer [CWE-401]假阳性?
EN

Stack Overflow用户
提问于 2020-06-15 08:49:40
回答 1查看 183关注 0票数 1

最近我了解到GCC的新-fanalyzer特性,并决定在我们的代码库中试用它。结果很有趣,但是有一个函数我怀疑是假阳性。

这是一个有争议的函数,GCC报告了一个malloc泄漏(请看这里):

代码语言:javascript
复制
char** va_to_argv(va_list args, int32_t* argc)
{
    va_list a;
    char* arg;
    int32_t n;
    int32_t l;
    int32_t sz = 0;
    int32_t cnt = 0;

    va_copy(a, args);
    while ((arg = va_arg(a, char*)) != NULL)
    {
        sz += strlen(arg) + 1;
        ++cnt;
    }
    va_end(a);

    struct s
    {
        char* argv[cnt + 1];
        char  data[sz];
    };

    struct s* tmp = calloc(1, sizeof(*tmp));

    for (n=0, l=0; n<cnt; ++n)
    {
        tmp->argv[n] = &tmp->data[l];
        strcpy(tmp->argv[n], va_arg(args, char*));
        l += strlen(tmp->argv[n]) + 1;
    }

    tmp->argv[cnt++] = NULL;

    if (argc)
    {
        *argc = cnt;
    }

    return &(tmp->argv[0]);
}

它应该将va_list (仅包含char*,并以NULL作为最后一个参数)转换为等效的argc/argv表示形式。据我所知,从来没有任何问题涉及到这个特定的功能,所以当GCC报告tmp在返回声明中被泄露时,我感到非常惊讶。

是的,calloc()的结果存储在tmp中,函数不直接返回tmp,因此乍一看,警告是有意义的。但是,返回的值是指向tmp的第一个元素的指针,结构的第一个元素的地址与结构本身的地址相同(因此free(&(tmp->argv[0]))应该是合法的)。

ISO/IEC 9899,第6.7.2.1节 指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。在structure对象中可能有未命名的填充,但在开始时没有。

不幸的是,这段代码依赖于特定于GCC的扩展(在struct中是VLA),而clang不支持这个扩展。否则,我会想要反复检查克郎的静态分析器对此有什么看法。

编辑

即使类型不匹配(正如Lundin指出的那样),警告仍然存在,即使在函数的这个版本中(当然,它不再做任何有意义的事情):

代码语言:javascript
复制
char** va_to_argv(va_list args, int32_t* argc)
{
    struct s
    {
        char** argv;
        char  data[10];
    };

    struct s* tmp = calloc(1, sizeof(*tmp));

    if (tmp == NULL) return NULL;

    return tmp->argv;
}
EN

回答 1

Stack Overflow用户

发布于 2020-06-15 09:31:01

没有VLA的简化版本:

代码语言:javascript
复制
char **va_to_argv(va_list args, int32_t *argc)
{
    va_list a;
    char *arg;
    char *data;
    char **arr;
    int32_t n;
    int32_t ii;
    int32_t sz = 0;
    int32_t cnt = 0;

    va_copy(a, args);
    for(cnt=0;  (arg = va_arg(a, char*)) ; cnt++ )
    {
        sz += 1+ strlen(arg) ;
    }
    va_end(a);


    data = malloc(sz+1);
    arr = calloc(cnt+1, sizeof *arr);

    for (n=ii=0; n<cnt; n++)
    {
        arr[n] = &data[ii];
        strcpy(arr[n], va_arg(args, char*));
        ii += 1 + strlen(arr[n]) ;
    }

    arr[n++] = NULL;

    if (argc) *argc = n;

    return arr;
}

编辑:如果只想分配一个对象,可以在*char[]数组之后定位char[]数组,然后返回指针数组:

代码语言:javascript
复制
arr = malloc(sz+1 + (cnt+1) * sizeof *arr);
data = (char*) ( &arr[cnt+1] ); // Put data after the last arr[] element
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62384605

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档