I have a compiler warning I would like to get rid off.
warning: the argument to '__builtin_assume' has side effects that will be discarded [-Wassume]
C:\Keil_v5\ARM\ARMCLANG\Bin..\include\assert.h(72): note: expanded from macro 'assert'
define assert(e) ((e) ? (void)0 : _CLIBNS _aeabi_assert(e, _FILE__, _LINE__), (__ARM_PROMISE)((e)?1:0))
The idea is to have no warning when compiled with warning set to "pedantic".
The cause is a recently added pointer check function to my embedded code. The idea is to improve the following:
void foo(int* const val)
{ assert(val != NULL);
/*Use val etc.*/
}
to something along the lines of:
void foo(int* const val)
{ assert(checkPtr(val) == OK);
/*Use val etc.*/
}
This is because automatic variables are not zero intialised. Thus, it is likely that an uninitialised pointer will not be NULL. This is a coding mistake that I would like to detect (not necessarily my own doing), hence the checks. The following is not perfect, but does seem to pick up more pointer errors (not dangling ones unfortunately).
I have the following code in a header file to implement this:
#define INTERNAL_RAM_START ((uintptr_t)0x2000000UL)
#define INTERNAL_RAM_END (INTERNAL_RAM_START + (uintptr_t)0x20000UL)
#define INTERNAL_ROM_START ((uintptr_t)0x8000000UL)
#define INTERNAL_ROM_END (INTERNAL_ROM_START + (uintptr_t)0x100000UL)
typedef enum{OK, NOT_OK}Status_t;
static inline Status_t checkPtr(const void* const ptrToCheck)
{
if(ptr == NULL)
return NOT_OK;
const uintptr_t ptr = (uintptr_t)ptrToCheck;
if((ptr >= INTERNAL_RAM_START) && (ptr < INTERNAL_RAM_END))
return OK;
if((ptr >= INTERNAL_ROM_START) && (ptr < INTERNAL_ROM_END))
return OK;
return NOT_OK
}
I don't have any warnings with ARMCC 5.06 in my code. From what I can see, my checkPtr function does not have any side effects. It does not access any variables other than the pointer that was passed to it.
The documentation suggests that armclang supports the __attribute__ ((pure)) and __attribute__ ((const)) function attributes. These attributes are for functions that don't have any side effect, their return value is based on the input parameters. A pure function can also read global state, while a const function can only examine its function parameters.
Adding one of these attributes to your checkPtr declaration and definition should silence the warning.
Related
I wonder if there is a way to check a pointer's validity besides the common assert(NULL != ptr).
I tried the following to intentionally provoke an "access error" so i will be alerted early, not lately when the pointer is accessed in some nested code:
#if !defined _NDEBUG || defined _DEBUG
#define _check_ptr(ptr, type) do{type x; assert(NULL != ptr); x = *ptr;}while(0)
#else
#define _check_ptr(ptr, type)
#endif
Any recommondations about this topic?
Desired usecase:
void func(int *ptr){
_check_ptr(ptr, int);
if (NULL != ptr){ // Still check in release
...
}
}
As a precondition it would be perfectly acceptable to rely upon the IDE throwing me into the debugger on access error. In my case i will not run the debug build from command line or from somewhere outside the IDE.
I don't believe this is a duplicate because the function does return in the happy path. Using the attribute no-return allows the compiler to optimise on the assumption that the function never returns, which is not the case here.
I have come C code that either returns a pointer or calls another function to exit out of the program. This is in an if statement, so either it returns the result or exits. As the function returns a void *, the compiler warns that it's possible the function won't return a value (which is of course true):
error: control reaches end of non-void function [-Werror=return-type]
I can get around this by just adding return *temp; to the end of the function but I'd like to be clear in my intent by having something like the unused variable attribute:
__attribute__((__unused__))
That way I can leave -Wall on and not have to add unnecessary or possibly confusing code.
I'd also be up for rewriting the code if there's a better way to express this intent.
The code looks something like:
void *get_memory() {
void *temp = malloc(100);
if (temp) {
// do some setup work
return temp;
} else {
exit_program_with_epic_fail();
}
// Compiler warns if the following line isn't present
return temp;
}
There are 2 ways to get rid of the warning:
tag the exit_program_with_epic_fail() function with the appropriate attribute, _Noreturn in C11, but there is no portable way to do this to pre-C11 compilers. Many compilers support __attribute__((noreturn)), notably gcc, clang and tinycc, but it is an compiler specific extension.
reorganise the code to let the compiler see the function always return.
Here is a modified version:
void *get_memory(void) {
void *temp = malloc(100);
if (!temp) {
exit_program_with_epic_fail();
}
// do some setup work
return temp;
}
This seems to be a pure design problem.
The warning/error "control reaches end of non-void function" isn't the problem, it is rather just an indicator telling you where the actual problem is.
You could/should simply rewrite the function as
void *get_memory (void)
{
void *temp = malloc(100);
if(temp != NULL)
{
// do stuff
}
return temp;
}
And leave error handling to the caller. Because it is not an allocation function's job to terminate the application - that's bad design.
Alternative version with detailed error handling:
typedef enum
{
OK,
ERR_OUTOFMEMORY,
...
} err_t;
err_t get_memory (void** mem)
{
*mem = malloc(100);
if(*mem == NULL)
{
return ERR_OUTOFMEMORY;
}
// do stuff
return OK;
}
The problem is this:
#define do_stuff(ret) ((ret) ? getstuff(ret) : 0)
int var;
do_stuff(&var);
test.h:34:46: warning: the address of 'var' will always evaluate as 'true' [-Waddress]
do_stuff acts as a function that accepts an output-pointer that can be NULL, though, thus the warning is not helpful but annoying.
Is there a way via code to make gcc stop complaining? Maybe an (at least kind of) portable one?
Btw. do_stuff has to be a macro as ret actually gets set in a generic way (here stripped for simplicity).
Edit:
Again, I just want to have the usual output-pointer that can be NULL, but inside a macro instead of a function. The actual code looks like this:
#define retrieve(x, ret) \
( ret ? (*ret = x.buf[0], 1) : 0 )
which gave the warning from above when using it like retrieve(stuff, NULL). Accordingly to Adriano Repetti's answer, I changed it to:
#define retrieve(x, ret) \
( ((void *)ret != NULL) ? (*ret = x.buf[0], 1) : 0 )
which works, but now gives me warning: dereferencing 'void *' pointer as this gets expanded to ( ((void *)NULL != NULL) ? (*NULL = x.buf[0], 1) : 0 ). Is there a way I can get rid of this warning, too?
retrieve has to be a macro because x.buf is of variant type, and so is ret, passing it through a function like in 2501's tip would result in type loss.
Assuming you really can't avoid a macro and considering that I wouldn't disable warnings (even if this particular one isn't dangerous) then I'd cheat compiler with some casts. Code will be portable and no warnings will be emitted:
#define do_stuff(ret) (((uintptr_t)NULL != (uintptr_t)ret) ? getstuff(ret) : 0)
Central point here is simply this: (uintptr_t)NULL != (uintptr_t)ret. I'd suggest to also read this post here on SO. Note that also simply NULL != (void*)ret works.
You can add a dummy function that just returns the pointer, this might silence the compiler:
void* pass( void* a )
{
return a ;
}
#define do_stuff(ret) ( pass(ret) ? getstuff(ret) : 0)
int var;
do_stuff( &var );
GCC's -Waddress command line flag is used to disable this type of warnings. But it's better to write your code without warnings.
I'm working on a macro that will support error handling.
#define Try(e, call) ( (e == OK) && ((e = call) != OK) )
It can be used as the expression of an if-statement:
if (Try(err, SomeFunction(foo, bar))) {
// Entered only if err was OK before the if-statement and SomeFunction()
// returned a non-OK value.
}
The function won't be called if err was already non-OK before the if-statement. After the if-statement err will be set to the return value of SomeFunction().
So far so good. However I also want to use the macro without an if-statement:
Try(err, SomeFunction(foo, bar));
In this case GCC gives the following warning:
warning: value computed is not used [-Wunused-value]
And that's what my question is about: how can I rewrite the macro such that GCC won't produce this warning. I know the warning can be disabled with a flag (but I want to keep it enabled for other code) or by casting the result explicitly to void. The following statement code won't produce the warning:
(void) Try(err, SomeFunction(foo, bar));
But it's far from ideal to prefix each Try() with a void cast. Any suggestions?
You can use the ternary operator like this:
( (e == OK) ? ((e = call) != OK) : (e == OK) )
I'd go for something like this
inline
bool notOK(int err) {
return err != OK;
}
#define Try(e, call) ( !notOK(e) && notOK(e = call) )
Usually compilers don't complain about function return values that are not used.
For debugging purposes it might be necessary also to add an "instantiation"
bool notOK(int err);
in a .c file.
Just an idea.
static inline int identity (int x) { return x; }
#define Try(e, call) (identity ((e == OK) && ((e = call) != OK)))
You may want to #define inline __inline__ or #define inline /*nothing*/ for non-gcc compilers.
I would like to force a functions parameters to accept only specific definitions. For example, consider #define OUTPUT 1, #define INPUT 0 and void restrictedFunction(int parameter); .
How would I force restrictedFunction(int parameter) to accept only OUTPUT or INPUT?
I would also like to take into consideration that another definition may have the same value, for example, #define LEFT 1 and #define RIGHT 0.
So in this case I would like restrictedFunction(int parameter) to be able to accept only OUTPUT and INPUT specifically.
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
void restrictedFunction(IO_Type parameter) { ... }
It doesn't absolutely force the use of the values (the compiler will let someone write restrictedFunction(4)), but it is about as good as you'll get.
If you truly want to force the correct type, then:
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
typedef struct { IO_Type io_type } IO_Param;
void restrictedFunction(IO_Param parameter) { ... }
In C99 or later, you could call that with:
restrictedFunction((IO_Param){ INPUT });
This is a compound literal, creating a structure on the fly. It is not entirely clear that the structure type really buys you very much, but it will force the users to think a little and may improve the diagnostics from the compiler when they use it wrong (but they can probably use restrictedFunction((IO_Param){ 4 }); still).
What this means is that your restrictedFunction() code should be ready to validate the argument:
void restrictedFunction(IO_Type io_type)
{
switch (io_type)
{
case INPUT:
...do input handling...
break;
case OUTPUT:
...do output handling...
break;
default:
assert(io_type != INPUT && io_type != OUTPUT);
...or other error handling...
break;
}
}
You could use an enum.
typedef enum TrafficDirection { INPUT = 0, OUTPUT = 1 } TrafficDirection;
restrictedFunction(TrafficDirection direction);
of course, this isn't perfect. You can still pass any int to it as long as you use a cast.
restrictedFunction((TrafficDirection) 4);
You don't get quite as much protection as you might like, but you can do:
enum func_type { INPUT, OUTPUT };
void restrictedFunction( enum func_type parameter );
You can use a wrapper to validate the argument:
#define restrictedFunction(x) do { \
static_assert((x) == INPUT || (x) == OUTPUT); \
assert(!strcmp(#x, "INPUT") || !strcmp(#x, "OUTPUT")); \
restrictedFunction(x); \
} while(0)
Notes:
This assumes restrictedFunction() returns a void. If it returns a value which you actually use, you'll need something like gcc's compound statement http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html. Or--better--you can use BUILD_BUG_ON_ZERO (see What is ":-!!" in C code?), which I keep forgetting about, because it doesn't seem to work with C++.
The do ... while(0) is to "swallow the semi-colon"; not really relevant here.
static_assert() is a compile-time assert; there are many variants available. Here is a link to one, https://stackoverflow.com/a/9059896/318716, if you don't have your own handy.
assert() is the standard run-time assert.
With gcc 4.1.2, and my version of static_assert(), you can replace the run-time assert() with a compile-time assert when the two !strcmp()'s are replaced with ==; see example below. I haven't tested this with other compilers.
x is only used once in the macro expansion, since the first four references are only used at compile-time.
When your actually define your function, you'll have to add parentheses to disable the macro expansion, as in:
void (restrictedFunction)(int x){ ... }
Also, if your code has a special case (whose code doesn't?) where you need to call restrictedFunction() with the argument foo, you'll need to write:
(restrictedFunction)(foo);
Here is a complete example, which puts a wrapper around the standard library function exit():
#include <stdlib.h>
#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum{EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}
#define exit(x) do { \
ASSERTM((x) == EXIT_SUCCESS || (x) == EXIT_FAILURE, value); \
ASSERTM(#x == "EXIT_SUCCESS" || #x == "EXIT_FAILURE", symbol); \
exit(x); \
} while(0)
int main(void) {
exit(EXIT_SUCCESS); // good
exit(EXIT_FAILURE); // good
exit(0); // bad
exit(3); // doubly bad
}
If I try to compile it, I get:
gcc foo.c -o foo
foo.c: In function 'main':
foo.c:17: error: enumerator value for 'symbol_ASSERT_line_17' is not an integer constant
foo.c:18: warning: division by zero
foo.c:18: error: enumerator value for 'value_ASSERT_line_18' is not an integer constant
foo.c:18: error: enumerator value for 'symbol_ASSERT_line_18' is not an integer constant