Jack Brennen
Jack Brennen

Reputation: 413

Why do gcc and clang silently allow a standard include file to redefine macros?

Example code:

#define PROT_NONE 99
#include <sys/mman.h>

Both gcc and clang permit the above code fragment to compile; the PROT_NONE macro is redefined from within sys/mman.h with no warning. Looking at the actual header file, there is no #undef which would permit a redefinition.

This seems like a problem -- although this case is obviously contrived to show the problem, it does seem that identifier collisions between my code and the system header files can be silently ignored. The system header definition of PROT_NONE overrides my definition and doesn't even warn me that there's a potential problem. This seems to be specific to the system header file somehow; if I try to do the redefinition myself, I get the proper error.

My question is basically twofold:

Upvotes: 1

Views: 915

Answers (2)

H Walters
H Walters

Reputation: 2674

What's happening/motivation

In both gnu and clang, warnings are suppressed in system headers.

The clang user manual just declares this is so:

Warnings are suppressed when they occur in system headers.

...but the gnu c preprocessor manual gives the following justification:

The header files declaring interfaces to the operating system and runtime libraries often cannot be written in strictly conforming C. Therefore, GCC gives code found in system headers special treatment.

Mitigation on the command line

Is there any command line switch that will cause this to fail at the compilation stage?

Yes. Make your system-headers non-system-headers.

In clang, you can do this merely with --no-system-header-prefix x/y/z, where x/y/z is a pattern matched starting at all system directories. For example, in your case, you can use --no-system-headers sys; or you can cherry pick further: --no-system-headers sys/mm (all files in a system directory included via the sys subdirectory that start with mm; it's just a prefix pattern, not a directory spec).

In gcc, this is a bit tricker. System headers by default are just headers in system directories, and there's no way to exclude a particular directory as a system directory. You can, however, ditch all system directories with -nostdinc, and add them back in as regular inclusion directories. For example:

gcc -nostdinc -I/usr/include -I/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include ...

You need -nostdinc; -I paths into your system inclusion paths just winds up being ignored.

Upvotes: 3

Florian Weimer
Florian Weimer

Reputation: 33717

GCC suppresses warnings in system headers by default. The reason is that the user usually cannot do anything about warnings generated by those headers because they cannot edit the code to fix those warnings. You can enable those warnings using -Wsystem-headers.

For your specific example, a redefinition of a macro not defined in a system header by a system header, GCC should probably warn even with -Wno-system-headers (it now has the infrastructure to do that). Someone already filed an RFE:

Upvotes: 2

Related Questions