GCC warning to identify copying structures that contains pointers - c

Is there any GCC warning that cautions when I try to copy structures containing pointers with assignment operator instead of deep copying?

The answer is no. See the list of gcc warning options.
Given the same page, warnings are:
Warnings are diagnostic messages that report constructions that are not inherently erroneous but that are risky or suggest there may have been an error.
And shallow copy instead of a deep copy is neither risky nor erroneous as it may be an intended behavior. So there is no reason for such warning option to exist.
What you may want is a static analyzer such as clang's one, though in my knowledge this one doesn't offer that kind of functionality.

I remember seeing precisely such a warning with -Weffc++
Of course, you'd have to be willing to compile in c++ mode. (See below)
Edit I tested it: Sadly, this won't warn about POD (i.e.) C types. Here is the test:
struct HasPointer
{
int* resource;
HasPointer() {};
~HasPointer() {};
};
Compiled with
E:\mingw64>g++ test.c -Weffc++
Outputs
test.c:1:8: warning: 'struct HasPointer' has pointer data members [-Weffc++]
struct HasPointer
^
test.c:1:8: warning: but does not override 'HasPointer(const HasPointer&)' [-Weffc++]
test.c:1:8: warning: or 'operator=(const HasPointer&)' [-Weffc++]
test.c: In constructor 'HasPointer::HasPointer()':
But leaving the ctor/dtor out, the warning isn't even emitted, so this option doesn't work for your code, even in C++ compile mode.
Compiling C code in C++ mode:
(Use extern "C") to achieve binary interoperability. It is usually as simple as
extern "C"
{
# include "my.h"
# include "stuff.h"
// ...
}

Related

How can I remove the warning in GCC 4.6: "missing initializer [-Wmissing-field-initializers]"?

The code
GValue value = { 0 };
gives the following warning:
missing initializer [-Wmissing-field-initializers]
I know that's a GCC bug, but is there some trick to remove it? It is really not nice see such unreal warnings. But I don't want power off the warning because it will hide real warnings from me too. And sorry, but I can't update my GCC to 4.7 (where looks like it was fixed) version, yet.
Use G_VALUE_INIT to initialize GValue-s. Their (private) structure is in /usr/include/glib-2.0/gobject/gvalue.h which #define G_VALUE_INIT appropriately.
I strongly disagree with your assessment that it is GCC's bug. You ask to be warned if a field is not explicitly initialized with -Wmissing-field-initializers and you get the warning you deserve.
Sadly G_VALUE_INIT is not documented, but it is here. Code with
GValue value = G_VALUE_INIT;
There is no universal solution to never get the warning about missing field initialization if -Wmissing-field-initializers is asked. When you ask for such a warning, you require the compiler to warn of every incomplete initializers. Indeed, the standard requires than all the non-explicitly initialized struct fields be zeroed, and gcc obeys the standard.
You could use diagnostic pragmas like
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
But my feeling is that you should code with care, and explicitly initialize all the fields. The warning you get is more a coding style warning (maybe you forgot a field!) than a bug warning.
I also believe that for your own (public) struct you should #define an initializing macro, if such struct are intended to be initialized.
You could use:
-Wno-missing-field-initializers
to inhibit that warning specifically. Conversely, you could make it into an error with:
-Werror=missing-field-initializers
Both of these work with GCC 4.7.1; I believe they work with GCC 4.6.x too, but they don't work with all earlier versions of GCC (GCC 4.1.2 recognizes -Wno-missing-field-initializers but not -Werror=missing-field-intializers).
Obviously, the other way to suppress the warning is to initialize all fields explicitly. That can be painful, though.
It also appears that using the .field-style of initialization, such as:
GValue value = { .somefield = 0 };
will cause the compiler to not issue the warning. Unfortunately if the struct is opaque, this is a non-starter.

mkdtemp requires _DARWIN_C_SOURCE for unistd.h

I am a little puzzled. I have project that I compile with
CFLAGS=-g -O2 -Wall -Wextra -Isrc/main -pthread -rdynamic -DNDEBUG $(OPTFLAGS) -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=700
Now I want to use mkdtemp and therefor include unistd.h
char *path = mkdtemp(strdup("/tmp/test-XXXXXX"));
On MacOSX the compilation gives some warnings
warning: implicit declaration of function ‘mkdtemp’
warning: initialization makes pointer from integer without a cast
but compiles through. While mkdtemp does return a non-NULL path accessing it results in a EXC_BAD_ACCESS.
Question 1: The template is strdup()ed and the result is non-NULL. How on earth can this result in an EXC_BAD_ACCESS?
Now further down the rabbit hole. Let's get rid of the warnings. Checking unistd.h I find the declaration hidden by the pre processor.
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
...
char *mkdtemp(char *);
...
#endif
Adding -D_DARWIN_C_SOURCE to the build makes all the problems go away but leaves me with a platform specific build. The 10.6 man page just says
Standard C Library (libc, -lc)
#include <unistd.h>
Removing the _XOPEN_SOURCE from the build makes is work on OSX but then it fails to compile under Linux with
warning: ‘struct FTW’ declared inside parameter list
warning: its scope is only this definition or declaration, which is probably not what you want
In function ‘tmp_remove’:
warning: implicit declaration of function ‘nftw’
error: ‘FTW_DEPTH’ undeclared (first use in this function)
error: (Each undeclared identifier is reported only once
error: for each function it appears in.)
error: ‘FTW_PHYS’ undeclared (first use in this function)
Question 2: So how would you fix this?
The only fix I have found is to #undef _POSIX_C_SOURCE right before the unistd.h include ...but that feels like an ugly hack.
You've asked two questions here, and I'm just going to answer the first:
Question 1: The template is strdup()ed and the result is non-NULL. How on earth can this result in an EXC_BAD_ACCESS?
As the warnings above tell you:
warning: implicit declaration of function ‘mkdtemp’
This means it couldn't find the declaration for mkdtemp. By C rules, that's allowed, but it's assuming the function returns an int.
warning: initialization makes pointer from integer without a cast
You've told the compiler "I've got a function that returns int, and I want to store the value in a char*". It's warning you that this is a bad idea. You can still do it, and therefore it compiles.
But think about what happens at runtime. The actual code you link to returns a 64-bit char*. Then your code treats that as a 32-bit int that it has to cast to a 64-bit char*. How likely is that to work?
This is why you don't ignore warnings.
And now for the second question:
Question 2: So how would you fix this?
Your problem is that you're explicitly passing -D_XOPEN_SOURCE=700, but you're using a function, mkdtemp, that isn't defined in the standard you're demanding. That means your code shouldn't work. The fact that it does work on linux doesn't mean your code is correct or portable, just that you happened to get lucky on one platform.
So, there are two rather obvious ways to fix this:
If you want to use _XOPEN_SOURCE=700, rewrite your code to only use functions that are in that standard.
If you've only added _XOPEN_SOURCE=700 as a hack that you don't really understand because it seemed to fix some other problem on linux, find the right way to fix that problem on linux.
It may turn out that there's a bug on one platform or another so there just is no right way to fix it. Or, more likely, you're using a combination of non-standard functions that can be squeezed in on different platforms with a different set of flags on each. In that case, your Makefile (or whatever drives the build) will have to pass different flags to the compiler on different platforms. This is pretty typical for cross-platform projects; just be glad you only have one flag to worry about, and aren't building 3000 lines worth of autoconf.

implicit int and implicit declaration of functions with gcc compiler

I read in the c99 Standard:
-remove implicit function declaration,
-remove implicit int.
But when I try to compile this code with gcc compiler in c99 mode using -pedantic
main(void){
f(3);
return 0;
}
int f(int a){
....
}
I expect 2 errors, but I just receive 2 warnings:
-warning: return type defaults to ‘int’
-warning: implicit declaration of function ‘f’.
Shouldn't them be errors in c99?
http://gcc.gnu.org/c99status.html
In both situations there's written "done".
Thanks.
The C standard requires a diagnostic for any translation unit containing a violation of a syntax rule or constraint. It does not require such diagnostics to be fatal; the compiler is free to continue processing the source file. The behavior of the resulting executable, if any, is undefined. The standard makes no distinction between warnings and fatal errors.
(The only thing that requires a compiler to reject a source file is the #error directive.)
Conclusion: when compiling C, take warnings very seriously.
I don't believe the compiler is required to produce a fatal error. Use -Werror if you're concerned...
Two points: first, it may (usually does) take a specific set of flags to get a compiler to conform with the standard.
Second, all that's required by the standard is that the implementation issue a "diagnostic" in the case of an error -- but it's up to the implementation to define what is or isn't a diagnostic. It's free to say a "warning" is a diagnostic if it wants to. When a diagnostic is issued, it may quit compiling, or it can compile the code anyway.
Bottom line: what it's doing is probably enough to conform, for whatever that's worth.

How to turn "implicit declaration" warnings in $CC into errors?

Preamble: My C may be fairly rusty; I first started writing C programs in somewhere around 1993 -- compilers may have been different back then, but I recall that when one attempted to refer to a C function that was not declared, the compiler would abort. This is from memory.
Currently, I am perplexed as to why GCC (4.4.3) is so forgiving on me when I [intentionally] mismatch or omit declaration of bar below, with its definition in bar.c. Because the compiler does not warn me, the program proceeds to a fatal addressing error at runtime -- since bar wants an address and is given an integer, it ends up de-referencing that integer as an address.
A strict compiler, or so I would think, would abort on me with an error. Am I missing something? My build command line is as follows:
cc -o foobar -g -Wall -std=c99 -fexec-charset=ISO-8859-1 -DDEBUG foo.c bar.c
With foo.c:
int main() {
int a;
bar(a);
return 0;
}
and bar.c:
void bar(int * a) {
*a = 1;
}
I have intentionally omitted declaration of bar and, as mentioned, intentionally pass it an integer (could be anything really) instead of an address that its actual definition would otherwise mandate. Because $(CC) does not stop me, I end up with a segmentation fault (x86, Ubuntu 10.04). I am aware that a compliant C (C99?) compiler would implicitly create an int bar(void) declaration for bar if none otherwise found, but in this case that's obviously not what I want at all!
I want to protect myself from the kind of errors -- where I make the human mistake of mismatching declarations and definitions or omitting the former altogether.
I tried to instead just invoke the compiler without the linking step (with the -c switch) -- but it doesn't matter as compiling still succeeds with warnings. The linker might complain though, but I want the compiler to stop me before that happens.
I do not actually want to turn all my warnings into errors (e.g. with -Werror), because:
I could have included the wrong float bar(double a); at the top of foo.c, which would eliminate the warning altogether, but doesn't change the fact that the resulting program crashes; alas, a program that compiles successfully without warnings (even with the -Wall switch) but still is faulty
I have and will have other types of warnings that should stay warnings and not prevent successfully building the program
It would be dealing with the effect of the problem, rather than the problem itself
It's not just the types of warnings, but also particular instances thereof; I wouldn't want to turn a specific warning into an error because in some instances that would not be applicable; this would be too "coarse" of a solution which doesn't take into account the specifics of and the context in which the warning occurred
To turn this warning into an error when compiling with gcc, pass the switch -Werror=implicit-function-declaration to the compiler.
Trying to answer your "why" question: yes, it might look odd that this is by default a warning and not an error. This is for historical reasons. For details, see e.g. Why does/did C allow implicit function and typeless variable declarations?, or read it in Ritchie's own words at http://cm.bell-labs.com/who/dmr/chist.html.
You could probably force additional warnings for gcc:
-Wmissing-prototypes
-Wmissing-declarations
Using both (along with -Werror) will probably help you to avoid such situations, but require some more code writing.
Inspired by this.
EDIT: Example
// file: mis1.c
int main(void)
{
int a;
bar(a);
return 0;
}
// file: mis2.c
#include <stdio.h>
double bar(double a)
{
printf("%g\n", a);
return a;
}
Compiling with gcc 3.3.4 (DJGPP) as:
gcc -Wall -Wmissing-prototypes -Wmissing-declarations -Werror mis2.c mis1.c -o mis.exe
Compiler output:
mis2.c:5: warning: no previous prototype for `bar'
mis1.c: In function `main':
mis1.c:6: warning: implicit declaration of function `bar'
Fix? #Include the following file in both files:
// file: mis.h
extern int bar(int);
Recompiling you get:
mis2.c:6: error: conflicting types for `bar'
mis.h:3: error: previous declaration of `bar'
Fix? Define and declare bar everywhere in the same way, correct, for example, mis.h:
// file: mis.h
extern double bar(double);
Likewise you could change bar() in mis2.c to match that of mis.h.
From the gcc docs on warnings:
-Wimplicit-function-declaration (C and Objective-C only)
Give a warning whenever a function is used before being declared. In C99 mode (-std=c99 or -std=gnu99), this warning is enabled by default and it is made into an error by -pedantic-errors. This warning is also enabled by -Wall.
...
-pedantic-errors (my emphasis) Like -pedantic, except that errors are produced rather than warnings.
...
-pedantic
Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used.
It looks to me that -pedantic-errors will do what you want (turn these warnings into errors), however it sounds like it will also turn on a host of other checks you may or may not want. =/
The closest I found to a solution to my problem was to simply use the flag -combine which indirectly causes the compiler to abort compilation when attempting to call a function that is missing a prototype or where prototypes mismatch or do not match the definition.
I am afraid it has drawbacks though. Since input files now are combined in one compilation run, one ends up with a single object file, which has some implications of its own. In short, -combine does something more than just fix my problem, and that may be a problem in itself.
You can turn all warning to error with
cc [..] -Werror [..]
. This will partially solve your problem.
I could have included the wrong float bar(double a); at the top of foo.c, which eliminates the warning altogether, but doesn't change
the fact that the resulting program crashes. Alas, a program that
compiles successfully without warnings (even with the -Wall switch)
and beautifully crashes at runtime.
Herefore it is essential, additional to other measures, to include the same header file (including the prototype) in foo.c and bar.c. This ensures that the correct prototype is applied at both places.

Is there a gcc command line option to silence warning: passing argument n discards qualifiers from type

I'm trying to compile -Wall -Werror and its cramping my style.
I'm trying to make explicit that certain arguments are constants and then passing them to non const qualifying functions inside a large library.
P.S. I was mostly doing this to try to make it clear that certain variables are constants, is it good or bad c style to do this when dealing with a library functions that don't use const?
If you are passing those constants into routines as reference parameters or by pointer, then there may be a damn good reason for those warnings. How do you know that those routines won't modify your "constants"? What is that gonna screw up in the rest of your code, which you told that those variables won't ever change?
If you really know for sure that what you are doing is safe, and there is no good way to recode things to get rid of the warning, you can turn some warnings off in gcc using pragmas. Do this for as small an area of code as possible, and comment why you are doing it.
Do not abuse this privelege, or you are liable to arrested by the code police and sentenced to 9 months of community service coding in Ada. That'll cure you of ever complaining about C's warnings again.
Use the -Wno-ignored-qualifiers switch.
Sometimes, when compiling with -Wall -Wextra -Werror (as I do too because it is very good practice), you face recurring warnings that you may want to disable project wide, or on a per source file basis. One that I disable often in my projects for instance is -Wno-long-long. This is not bad practice, because you know what you are doing, and you don't want to control third party code.
As I understand though, you are trying to disable the warning for specific parts of the code, since otherwise it would ruin your effort putting const everywhere. In this case, do:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
OffendingThirdPartyFunction(MyConstParam);
#pragma GCC diagnostic pop
or also (untested, I don't know where to put the semicolons, and I don't have a working GCC here at work)
#define NO_WARNING(expr) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wignored-qualifiers\"") \
expr \
_Pragma("GCC diagnostic pop")
NO_WARNING(OffendingThirdPartyFunction(MyConstParam));
Alternatively, you can use a cast. This is by far the most portable solution.
OffendingThirdPartyFunction((param_t*)MyConstParam);
Don't use a command-line option: the warning tells you that your code is not const-safe. It's right, your code isn't const-safe, although that's the fault of whoever wrote the library you're using.
If you disable the warnings then you won't get them any more even if you write code that's unsafe and it is your fault.
Instead, whenever one of the library functions takes a pointer-to-non-const, but guarantees not to modify the referand of the pointer, then cast the const-ness away from your pointer, and pass that. The cast serves as a record in the code that you (the programmer) are claiming that nothing invalid will happen, even though the type system can't prove that, and should probably be commented.
For example:
// in this library
void print_int(int *p) { printf("%d\n", *p); }
void set_int(int *p) { *p = 6; }
// your code
const int n = 5;
print_int((int*)(&n)); // warning suppressed for this call only,
// having carefully checked the print_int docs.
// further down your code
set_int(&n); // You *want* the compiler to stop this!
Or if you can be bothered (because you have a lot of such calls), write wrappers for the offending library functions:
void print_int_const(const int *p) { print_int((int*)(p)); }
// but no wrapper for set_int
Be aware that the cast also removes volatile (and in general accepts a lot of incorrect inputs). The overload prevents you accidentally using completely the wrong type, while the in-place cast doesn't.

Resources