gcc -Wnonnull-compare警告是否具有误导性?

mmvthczy  于 2024-01-08  发布在  其他
关注(0)|答案(2)|浏览(184)

我有一个API,其中一些函数是用nonnullGCC function属性声明的,例如:

  1. // declaration in .h
  2. __attribute__((nonnull))
  3. int foo(const char *bar);
  4. [...]
  5. // definition in .c
  6. int foo(const char *bar) {
  7. if (bar == NULL)
  8. return -1;
  9. // do something with bar
  10. ...
  11. }

字符串
但是NULL检查触发了**-Wnonnull-compareGCC警告。问题是nonnull**属性的文档说它:
使编译器检查调用[...]中的参数[...]是否为非空。
问题是它没有说明任何关于运行时的内容,所以如果我为了取悦GCC而删除这个检查,我可能会隐藏或在不必要的时候检测到调用程序中的错误。
那么在这种情况下,这个警告应该被静音吗?或者是文档中存在某种错误,使得没有检查的代码实际上是正确的?
FTR,我的编译器版本是11.4.0。

mqkwyuun

mqkwyuun1#

-Wnonnull-compare警告是否具有误导性?
没有。the GCC 11.4 documentation中有一个错误。它给出了nonnull属性的一个示例,其中它说:
例如,声明.使编译器检查在对my_memcpy的调用中,参数 destsrc 是否为非空。
然而,该属性的非示例描述性文本说了一些不同的东西(强调是添加的):
它表示引用的参数必须是非空指针。
这在the GCC 12.3 documentation中得到了纠正,其中有关示例的文本更改为:
例如,声明.通知编译器,在对my_memcpy的调用中,参数 destsrc 是非空的。
而非示例性描述性文本保持相同。
因此,nonnull属性是对编译器的Assert,它可以假设指针不为null,因此将非null指针与null进行比较的警告是正确的。
总之,nonnull属性没有提供您想要的功能,即当为不应该为null的参数传递null指针时报告。

oprakyz7

oprakyz72#

使用__attribute__((nonnull))似乎完全等同于将函数声明为:
int foo (const char bar[static 1])的值。“
在这两种情况下,您都与编译器编写了一个契约,上面写着“我保证这个参数永远不会是空指针,请相应地生成代码”。作为奖励,如果某些编译器可以在调用方推断传递了空指针,则它们还可能会给予诊断消息。
在检查vs NULL时,您会在函式内部得到诊断消息的原因是,您已经告诉编译器参数永远不会是null指标,所以检查是没有意义的。
如果你没有进行这种检查,编译器在调用端无法检测到一个传递的指针是空指针(可能是因为它发生在运行时),那么很可能会发生一些不好的事情,在这种情况下,这个属性并不是问题的解决方案。
那么,该怎么办呢?你已经在字里行间提出了正确的解决方案:
因此,如果我删除这个检查,以取悦GCC,我可能会隐藏,或检测到晚于必要的,在一个调用程序的错误。
调用程序中的错误应该会被调用程序检测到,这并不奇怪。因此,空指针检查应该在那里。理想的情况是尽可能接近指针由于某种原因可能变成空指针的情况。
正确用法示例:

  1. // caller application
  2. int* data = malloc(n);
  3. if(data == NULL) // <--- correct placement of the null pointer check
  4. { /* error handling */

字符串
错误用法示例:

  1. // caller application
  2. int* data = malloc(n);
  3. ...
  4. // 5k LoC later...
  5. some_unrelated_function(data);
  6. void some_unrelated_function (int* data)
  7. {
  8. if(data == NULL) // <--- WRONG PLACE
  9. }


值得注意的是:

  • bug应该尽可能早地被检测到。用户输入应该在获取用户输入的地方被净化,由获取用户输入的代码来净化。
  • 不相关的库函数不负责检测调用程序中的错误,也不负责清理用户输入,它们只应该执行指定的任务。
  • 垃圾ptr == NULL检查每一个无关的库函数会造成100%无用分支的显著执行时间开销。特别是如果库是性能关键的,例如数据复制函数等,可能会从循环中重复调用。这种多余的错误检查是C语言中常见的非老手错误。
展开查看全部

相关问题