我想要
int some_opaque_error_handler() __attribute__((returns_nonzero));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ equivalent of this
我使用的一个基于C/c++的库使用返回码来指示错误,这会导致编译器抱怨使用"unitalized";值。例如
int foo(int **ptr)
{
// detail not important here, just that:
// 1. compiler sees the contents of foo() from bar()
// 2. foo() has some kind of early return in error-path
// 3. precise return value of foo() from early return not known to the compiler
// 4. ptr is 100% properly initialized in non-error path (i.e. warning is
// indeed spurious)
if (ptr == 0xdeadbeef) {
return some_opaque_error_handler(...); // returns nonzero
}
*ptr = properly_initialize();
return 0;
}
int bar()
{
int *p;
if (foo(&p)) {
return /* continue propogating the error yadda yadda yadda */;
}
*p += 1; // Warning: p may be used uninitialized
}
在这种情况下,如果foo()
返回错误,*p
永远不会从bar()
访问,但由于错误处理程序是不透明的,编译器无法知道这一点。
是否有办法让编译器知道通过错误处理返回的几乎总是[1]非零(因此任何后续访问都不会发生?)[2]。我在运行静态分析程序时也遇到了类似的问题,因为它们也假设执行可能会继续超过这些点。
[1]用户可以更改错误处理程序的行为-尽管不太可能-返回0
,因此任何解决方案/编译器提示必须是非绑定的。
[2]是的,我知道我可以简单地初始化变量(,这是我目前所做的),但:
- 有一船这样的情况
- 这些警告似乎严重依赖于编译器、编译器版本、优化级别和土星环相对于银道面的方向
这感觉就像一场打地鼠游戏
如果你愿意使用宏,你可以把你的函数变成这样:
#define some_opaque_error_handler(...)
(some_opaque_error_handler(__VA_ARGS__) ?: -1)
这依赖于一个GCC扩展,如果中间操作数不为零,则省略中间操作数给出测试值。
如果你想避免使用扩展,你可以将逻辑嵌入到内联函数中。
static inline int return_nonzero (int exp) {
return (exp ? exp : -1);
}
/* ... */
#define some_opaque_error_handler(...)
return_nonzero(some_opaque_error_handler(__VA_ARGS__))
将该函数标记为写访问
__attribute__((__access__(__write_only__, 1)))
int foo(int **ptr) {
我想要
int some_opaque_error_handler() __attribute__((returns_nonzero));
你可以这样做:
#define some_opaque_error_handler()
__extension__({
int _x = some_opaque_error_handler();
if (_x == 0) __builtin_unreachable();
_x;
})
或呼叫站点相同。