Posted
on February 15, 2016, 11:54,
by mjw.
Like every new GCC release, GCC6 introduces a lot of new useful warnings. My favorite is still -Wmisleading-indentation. But there are many more that have found various bugs. Not all of them are enabled by default, but it makes sense to enable as many as possible when writing new code.
Duplicate logic
In GCC6 -Wlogical-op
(must be enabled explicitly) now also warns when the operands of a logical operator are the same. For example the following typo is detected:
points.c: In function 'distance':
points.c:10:19: warning: logical 'or' of equal expressions [-Wlogical-op]
if (point.x < 0 || point.x < 0)
^~
Similar logic for detection duplicate conditions in an if-else-if chain has been added with -Wduplicated-cond
. It must be enabled explicitly, which I would highly recommend because it found some real bugs like:
elflint.c: In function 'compare_hash_gnu_hash':
elflint.c:2483:34: error: duplicated 'if' condition [-Werror=duplicated-cond]
else if (hash_shdr->sh_entsize == sizeof (Elf64_Word))
~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
elflint.c:2448:29: note: previously used here
if (hash_shdr->sh_entsize == sizeof (Elf32_Word))
~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
GCC is correct, a Word in both an Elf32 and Elf64 file is 4 bytes. We meant to check for sizeof (Elf64_Xword) which is 8 bytes.
And with -Wtautological-compare
(enabled by -Wall
) GCC6 will also detect comparisons of variables against themselves which will always be true or false. Like in the case where we made a typo:
result.c: In function 'check_fast':
result.c:14:14: warning: self-comparison always evaluates to false [-Wtautological-compare]
while (res > res)
^
Finally -Wswitch-bool
(enabled by default) has been improved to only warn about switch statements on a boolean type if any of the case statements is outside the range of the boolean type.
Bit shifting
GCC5 already had warnings for -Wshift-count-negative
and -Wshift-count-overflow
. Both are enabled by default.
value.c: In function 'calculate':
value.c:7:9: warning: left shift count is negative [-Wshift-count-negative]
b = a << -3;
^~
value.c:8:9: warning: right shift count >= width of type [-Wshift-count-overflow]
b = a >> 63;
^~
GCC6 adds -Wshift-negative-value
(enabled by -Wextra
) which warns about left shifting a negative value. Such shifts are undefined because they depend on the representation of negative values.
value.c:9:10: warning: left shift of negative value [-Wshift-negative-value]
b = -1 << 5;
^~
Also added in GCC6 is -Wshift-overflow
(enabled by default) to detect left shift overflow.
value.c:10:11: warning: result of '10 << 30' requires 35 bits to represent, but 'int' only has 32 bits [-Wshift-overflow=]
b = 0xa << (14 + 16);
^~
You can increase the warnings given with -Wshift-overflow=2
(not enabled by default) which makes GCC also warn if the compiler can detect you are shifting a signed value that would change the sign bit.
value.c:11:10: warning: result of '1 << 31' requires 33 bits to represent, but 'int' only has 32 bits [-Wshift-overflow=]
b |= 1 << 31;
^~
NULL
The new -Wnull-dereference
(must be enabled explicitly) warns when GCC detects you (might) dereference a null pointer that will cause erroneous or undefined behavior (higher optimization levels might catch more cases).
dereference.c: In function 'test2':
dereference.c:30:21: error: null pointer dereference [-Werror=null-dereference]
if (s == NULL && s->bar > 2)
~^~~~~
-Wnonnull
(enabled by -Wall
) already warned for passing a null pointer for an argument marked with the nonnull
attribute. In GCC6 it has been extended to also warn for comparing an argument marked with nonnull
against NULL
inside a function.
nonnull.c: In function 'foo':
nonnull.c:8:7: error: nonnull argument 'bar' compared to NULL [-Werror=nonnull]
if (!bar)
^
C++
-Wterminate
(enabled by default) warns when a throw
will immediate result in a call to terminate
like in an noexcept
function. In particular it will warn when something is thrown from a C++11 destructor since they default to noexcept
, unlike in C++98 (GCC6 defaults to -std=gnu++14
).
collect.cxx: In destructor 'area_container::~area_container()':
collect.cxx:23:50: warning: throw will always call terminate() [-Wterminate]
throw sanity_error ("disposed while negative");
^
collect.cxx:23:50: note: in C++11 destructors default to noexcept
The help with some ODR issues GCC6 has -Wlto-type-mismatch
and -Wsubobject-linkage
.
C++ allows “placement new” of objects at a specified memory location. You are responsible for making sure the memory location provided is of the correct size. This might result in A New Class of Buffer Overflow Attacks. When GCC6 detects the provided buffer is too small it will issue a warning with -Wplacement-new
(enabled by default).
placement.C: In function 'S* f(S*)':
placement.C:9:27: warning: placement new constructing an object of type 'S' and size '16' in a region of type 'char [8]' and size '8' [-Wplacement-new=]
S *t = new (buf) S (*s);
^
And if you actually want less C++ then GCC6 will give you -Wtemplates
, -Wmultiple-inheritance
, -Wvirtual-inheritance
and -Wnamespaces
to help enforce coding styles that don’t like those C++ features.
Unused side effects
In GCC6 -Woverride-init-side-effects
(enabled by default) is its own warning when you use Designated Initializers multiple times with side effects. If the same field, or array element, is initialized multiple times, it has the value from the last initialization. But if any such overridden initializations has side-effects, it is unspecified whether the side-effect happens or not. So you’ll get a warning for such overrides:
side.c: In function 'foo':
side.c:18:68: warning: initialized field with side-effects overwritten [-Woverride-init-side-effects]
struct Secrets s = { .alpha = count++, .beta = count++, .alpha = count++ };
^~~~~
side.c:18:68: note: (near initialization for 's.alpha')
Before GCC6 -Wunused-variable
(enabled by -Wall
) didn’t warn for unused static const
variables in C. This was because some old code had constructs like: static const char rcs_id[] = "$Id:...";
. But this old special use case is not very common anymore. And not warning about such unused variables was hiding real bugs. So GCC6 introduces -Wunused-const-variable
(enabled by -Wunused-variable
for C, but not for C++). There is still some debate on how to fine tune this warning. So please comment if you find some time to experiment with it before GCC6 is officially released.
framed
Calling __builtin_frame_address
or __builtin_return_address
with a level other than zero (the current function) is almost always a mistake (it cannot be guaranteed to return a valid value and might even crash the program). So GCC6 now has -Wframe-address
(enabled by -Wall
) to warn about any such usage.