【发布时间】:2009-07-16 18:57:22
【问题描述】:
我们正在 Linux 内核中编写代码,因此,尽管我尽可能尝试,但我无法让 PC-Lint/Flexelint 在 Linux 内核代码上工作。内置符号等太多了。但这是一个附带问题。
我们有任意数量的编译器,从 gcc 开始,但也有其他的。随着时间的推移,它们的警告选项越来越强大,它们也是非常强大的静态分析工具。
这是我想要捕捉的。是的,我知道它违反了一些在代码审查中很容易发现的东西,例如“没有幻数”和“当心位移”,但前提是你碰巧看到了那段代码。无论如何,这里是:
unsigned long long foo;
unsigned long bar;
[... lots of other code ...]
foo = ~(foo + (1<<bar));
进一步更新了问题描述——即使 bar 限制为 16,仍然是个问题。澄清一下,问题是隐含的 int 类型的常量,它在计划外使复杂的表达式违反了所有计算都以相同的大小和符号进行的规则。
问题:'1' 不是 long long,但是,作为一个小值常量,默认为 int。因此,即使 bar 的实际值从未超过,例如 16,(1<<bar) 表达式仍然会溢出并破坏整个计算。
可能正确的解决方案:改写 1ULL。
是否有众所周知的编译器和编译器警告标志会指出这个(修订后的)问题?
【问题讨论】:
-
无论 int 的大小是多少,如果 bar 太大,则移位是未定义的(我认为。无论如何,有些不好)。您似乎要求编译器警告您第二个变量操作数要在 int 上移位。但是您说问题在于“1”并不长:您是否希望没有关于长变量移位的警告?我不明白为什么编译器编写者会期望该警告有用,而关于
-
@onebyone:假设
int是32 位,long long是64,~(foo + (1<<bar))仅适用于0<=bar<32,而~(foo + (1LL<<bar))适用于0<=bar<64。我假设当写前者而不是后者时,OP 想要一个警告。 -
当然,但是如果 foo 是 int 并且 bar 在逻辑上被限制(但不是按类型)为 1 或 2,他是否希望发出警告? foo 是 long long 而 bar 是 1 还是 2 怎么样?由于溢出结果未定义,对任何有符号常量进行乘法或加法的警告?编译器通常无法识别逻辑约束,因此我希望任何此类警告都极易出现误报。并不意味着这是一个坏主意,我只是在猜测为什么很难定义它应该是什么,并且无论如何编译器编写者的优先级很低。
-
如果编译器警告隐式加宽强制转换(即
(int)(1<<bar)到(long long)(1<<bar)可以解决 OP 的情况,但我看不到任何类似的选项。更不用说,像有人说,它会产生很多误报......
标签: c static-analysis compiler-warnings bit-shift integer-overflow