Reputation: 1130
TL;DR: I want
int some_opaque_error_handler() __attribute__((returns_nonzero));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ equivalent of this
A C/C++-based library I use uses return-codes to indicate errors, which causes the compiler to complain about using "unitialized" values. For example
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
}
In this case *p
is never accessed from bar()
if foo()
returns an error, but since the error handler is opaque the compiler cannot know this.
Is there anyway to let the compiler know that returning via error handler is almost always[1] nonzero (and hence any subsequent accesses never occur?)[2]. I have similar issues running static analyzers, since they too assume that execution may continue past such points.
[1] Users may change the behavior of the error handler to -- as unlikely as it may be -- return 0
so any solution/compiler hint must be nonbinding.
[2] Yes I know I can simply initialize the variables (which is what I currently do) but:
So this feels like an unwinnable game of whack-a-mole
Upvotes: 5
Views: 360
Reputation: 70472
If you are willing to use a macro, you can hack your function to look like this:
#define some_opaque_error_handler(...) \
(some_opaque_error_handler(__VA_ARGS__) ?: -1)
This relies on a GCC extension where leaving out the middle operand gives the tested value if it is non-zero.
If you want to avoid using an extension, you can embed the logic into an inlined function.
static inline int return_nonzero (int exp) {
return (exp ? exp : -1);
}
/* ... */
#define some_opaque_error_handler(...) \
return_nonzero(some_opaque_error_handler(__VA_ARGS__))
Upvotes: 2
Reputation: 141483
Mark the function as accessing for write.
__attribute__((__access__(__write_only__, 1)))
int foo(int **ptr) {
I want
int some_opaque_error_handler() __attribute__((returns_nonzero));
You would do this:
#define some_opaque_error_handler() \
__extension__({ \
int _x = some_opaque_error_handler(); \
if (_x == 0) __builtin_unreachable(); \
_x; \
})
or the same on calling site.
Upvotes: 0