【问题标题】:modulo size_t yields "The result of expression ' ' is undefined"模 size_t 产生“表达式''的结果未定义”
【发布时间】:2021-07-03 11:38:21
【问题描述】:

在 64 位系统上,当使用模运算符和 size_t 类型时,我从 clang 分析器收到以下警告:

htable.c:38:62: warning: The result of the ' ' expression is undefined [clang-analyzer-core.UndefinedBinaryOperatorResult]
return ht->num_buckets > 0 ? (ht->hash_fn(key, ht->seed) % ht->num_buckets)
                                                         ^

Complete trace

hash函数的结果有size_t,桶数也有size_t。最终这转化为无符号长。 AFAIK 结果不能为负,我检查了桶数是否为零。

哈希函数可能会溢出,但由于它用于链接哈希表,因此不会导致问题(如果我没记错的话)。

这里有什么问题? 这是误报吗?

出现警告的函数:

static size_t
htable_bucket_idx(htable_t* ht, void* key)
{
    if (!ht || !key) {
        printf("htable - bucket_idx: Invalid Argument!\n");
        exit(-1);
    }

    return ht->num_buckets > 0 ? (ht->hash_fn(key, ht->seed) % ht->num_buckets)
                               : ht->hash_fn(key, ht->seed);
}

哈希函数是 FNV 哈希函数的粗略简化版本:

size_t
fnv_hash_ul(const void* in, unsigned int seed)
{
    size_t             h     = seed;
    const unsigned int prime = 0xFDCFB7;
unsigned long ul = *((unsigned long*) in);

    return (h ^ ul) * prime;
}

htable_t的定义(为简洁起见省略其他类型,根据要求附加)

typedef size_t (*htable_hash)(const void* in, unsigned int seed);

typedef struct htable
{
    htable_hash      hash_fn;
    htable_keq       keq;
    htable_cbs_t     cbs;
    htable_bucket_t* buckets;
    size_t           num_buckets;
    size_t           num_used;
    unsigned int     seed;
} htable_t;

函数的调用:

static int
htable_add_to_bucket(htable_t* ht, void* key, void* value, bool rehash)
{
    if (!ht || !key) {
        printf("htable - add_to_bucket: Invalid Argument!\n");
        exit(-1);
    }
    size_t idx = htable_bucket_idx(ht, key);

    [...]

编译器信息:

clang version 11.1.0
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-pc-linux-gnu/10.2.0
Candidate multilib: .;@m64

htable.c on GitHub
htable.h on GitHub

【问题讨论】:

  • htable_t的定义是什么?您使用的是什么编译器/版本以及如何调用它?
  • 用所需信息更新了问题。
  • @SomeUsername1 ht->num_buckets 未初始化时是否有可能调用该函数?
  • @SomeUsername1 我尝试了您的代码序列的一个最小示例,它似乎可以正常工作here 启用clang-tidy
  • @Zoso:original code 确实会出现警告。这更奇怪,因为其余的代码不应该是相关的。

标签: c clang clang-static-analyzer clang-tidy


【解决方案1】:

实际上,这似乎是误报。我可以通过更改 htable_rehash() 来消除所有警告:

static int htable_rehash(htable_t* ht)
{
...
    ht->num_buckets <<= 1UL;
...
}

static int htable_rehash(htable_t* ht)
{
...
    ht->num_buckets *= 2;
...
}

很奇怪。

【讨论】:

  • 我玩了一下,我还发现各种明显不相关的更改使警告消失了。这可能值得为 clang-tidy 报告错误。
  • 我很好奇还有哪些其他变化导致分析器改变其行为。请详细说明一下好吗?
  • 添加空格会让警告再次出现。误报的指示也是消息“表达式的结果未定义”,其中编译器无法说明抱怨的表达式。
  • &lt;&lt;= 1UL 替换为 *= 2 或 ` = 2 * ht->num_buckets` 未能解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
相关资源
最近更新 更多