代码限定 - 在libc的qsort

时间:2016-06-17 14:00:32

标签: c gcc clang warnings signed

在对安全性至关重要的代码进行验证时 - 并且应该在嵌入式设备中执行 - 我看到了GCC和Clang发出的一些警告。警告很容易重现,因为有问题的代码来自开源BSD libc:

$ wget https://raw.githubusercontent.com/freebsd/\
freebsd/af3e10e5a78d3af8cef6088748978c6c612757f0/lib/libc/stdlib/qsort.c

$ gcc -c -Wall -Wsign-compare -DI_AM_QSORT_R -Wall qsort.c

qsort.c: In function 'qsort_r':
qsort.c:45:24: warning: comparison between signed and unsigned 
               integer expressions [-Wsign-compare]

#define MIN(a, b) ((a) < (b) ? a : b)
                        ^
qsort.c:186:6: note: in expansion of macro 'MIN'
  r = MIN(pd - pc, pn - pd - es);
      ^
qsort.c:45:34: warning: signed and unsigned type in conditional 
               expression [-Wsign-compare]
 #define MIN(a, b) ((a) < (b) ? a : b)
                                  ^
qsort.c:186:6: note: in expansion of macro 'MIN'
  r = MIN(pd - pc, pn - pd - es);

了解这些警告(从GCC和CLang发出)......

  • pdpcpn 是指针
  • essize_t(即 unsigned

可以认为C处理有符号和无符号实体之间比较的规则可以充分表达为DON'T, FOR THE LOVE OF GOD [1]

但在这种情况下,qsort的BSD实现比较......

  • 减去两个指针(具有签名类型ptrdiff_t
  • 的结果
  • 减去两个指针的结果,减去es - 这是无符号的。

为什么从unsigned中减去ptrdiff_t值(即有符号值)会产生unsigned个值?这是你在上面引用的帖子中可以阅读的内容。可以说,对于字大小的实体,signed OPERATOR unsigned的任何表达式都会产生unsigned类型。

所以,总而言之,为了让GCC和CLang停止抱怨,必须改变线路......

r = MIN(pd - pc, pn - pd - es);

要么:

r = MIN((unsigned)(pd - pc), pn - pd - es)

或者:

r = MIN(pd - pc, (signed)(pn - pd - es));

问题是......什么是正确的补丁?

[1] “为什么不在C / C ++中混合有符号和无符号值?”http://blog.regehr.org/archives/268

1 个答案:

答案 0 :(得分:0)

显然我自己在这里: - )

我对这个问题的回答来自一种非常简单的看待事物的方式......

如果您在左侧应用无符号演员表并重新编译,则目标文件不会更改(通过MD5总和进行验证)。如果您改为投射右侧(签名),则目标文件会发生变化 - 这意味着此更改与原始代码的作用相差(在汇编级别,至少 - 对于amd64和sparcs)。

简短回答:我继续投射到无符号(size_t)。这也是Apple seems to have done(感谢指针@alk)。