Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to workaround the GCC warning, "the address of XXX will never be NULL"?

I'm working on a C program. There is a function which takes two pointer arguments, call it cmp(). I present here a simplified stand-in for cmp() for illustrative reasons:

int cmp(struct foo *a, struct foo *b)
{
    return a->bar == b->bar;
}

I'd like to make a NULL-check macro, like this:

#define SAFE_CMP(a,b) (((a) != NULL && (b) != NULL) ? cmp((a),(b)) : 0)

I think this is perfectly fine. However, in when compiling with both -Wall and a compliation switch that regards a warning as an error, the following code is troublesome:

int baz(struct foo *a)
{
   struct foo b;
   /* ... */
   return SAFE_CMP(a, &b); 
}

since gcc warns that "the address of b will never be NULL".

Is there any way to workaround this situation? Having various helper macro like SAFE_CMP_1(safe_arg,unsafe_arg) and SAFE_CMP_2(unsafe_arg,safe_arg) etc. is the last thing I want. I'd like to have one helper macro applicable to all situations.

like image 399
Chul-Woong Yang Avatar asked Jul 01 '10 02:07

Chul-Woong Yang


People also ask

How do I ignore GCC warnings?

To answer your question about disabling specific warnings in GCC, you can enable specific warnings in GCC with -Wxxxx and disable them with -Wno-xxxx. From the GCC Warning Options: You can request many specific warnings with options beginning -W , for example -Wimplicit to request warnings on implicit declarations.

How does GCC treat warning errors?

The warning is emitted only with --coverage enabled. By default, this warning is enabled and is treated as an error. -Wno-coverage-invalid-line-number can be used to disable the warning or -Wno-error=coverage-invalid-line-number can be used to disable the error.


2 Answers

This seems to suppress the warning for me:

#define SAFE_CMP(a,b) (((void *)(a) != NULL && (void *)(b) != NULL) ? cmp((a),(b)) : 0)

...but personally, I would just create safe_cmp() as a function itself.

int safe_cmp(struct foo *a, struct foo *b) {
    return (a && b) ? (a->bar == b->bar) : 0;
}
like image 166
caf Avatar answered Nov 08 '22 03:11

caf


"I'd like to have one helper macro appricable to all situation."

Why? One size does not fit all. GCC is doing you a favor by telling you a comparison will always have a certain result. The address of a stack variable will never be NULL. I would just write out the check in baz:

int baz(struct foo *a) {
   struct foo b;
   ...
   return a == NULL ? 0 : cmp(a, &b);
}

You could also do it in cmp. It depends how you define the pre and post-conditions.

Another possible issue with your macro (not applicable for baz) is that a and b will be evaluated multiple times. Beware of:

SAFE_CMP(p++, p1++);
like image 44
Matthew Flaschen Avatar answered Nov 08 '22 03:11

Matthew Flaschen