gcc version - gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
Compiling below code with -Wall -Wuninitialized is throwing warning as expected
warning: ‘test’ is used uninitialized in this function [-Wuninitialized]
#include<stdio.h>
#include<stdlib.h>
void check (int test )
{
printf("%d",test);
}
int
main()
{
int test;
check(test);
return 0;
}
But compiling below code with -Wall -Wuninitialized is not throwing warning
#include<stdio.h>
#include<stdlib.h>
void check (int test )
{
printf("%d",test);
}
int
main()
{
int test;
int condition = 0;
if(condition == 27)
test = 10;
check(test);
return 0;
}
Shouldn't it throw warning?. is it anyway related to compiler optimization?
What an user understands as a false positive may be different for the particular
user. Some users are interested in cases that are hidden because of
actions of the optimizers combined with the current environment.
However, many users aren't, since that case is hidden because it
cannot arise in the compiled code. The canonical example is (MM05):
int x;
if (f ())
x = 3;
return x;
where 'f' always return non-zero for the current environment, and
thus, it may be optimised away. Here, a group of users would like to
get an uninitialized warning since 'f' may return zero when compiled
elsewhere. Yet, other group of users would consider spurious a warning
about a situation that cannot arise in the executable being compiled.
https://gcc.gnu.org/wiki/Better_Uninitialized_Warnings#Proposal
EDIT: MMO5 is already fixed
https://gcc.gnu.org/wiki/Better_Uninitialized_Warnings#MM05
Yes, gcc is not warning you because the code is optimized away. Some people think this is the right thing, because it might be that way by a compile time configuration value. Others think it's the wrong thing, because it hides possible mistakes.
You are not the first to notice this problem with GCC. There's a whole proposal about it.
clang with -Wall detects the problem and even suggests a fix.
$ make
cc -Wall -g test.c -o test
test.c:15:7: warning: variable 'test' is used uninitialized whenever 'if' condition is false
[-Wsometimes-uninitialized]
if(condition == 27)
^~~~~~~~~~~~~~~
test.c:18:10: note: uninitialized use occurs here
check(test);
^~~~
test.c:15:4: note: remove the 'if' if its condition is always true
if(condition == 27)
^~~~~~~~~~~~~~~~~~~
test.c:12:12: note: initialize the variable 'test' to silence this warning
int test;
^
= 0
1 warning generated.
Related
I'm trying to compile a large project (https://github.com/ESCOMP/CTSM). I would like to compile it as-is, without editing the code, if possible (it is known to build successfully on many platforms).
I'm using gcc (SUSE Linux) 11.2.1. and I get
In function ncmp : /run/media/dominic/hdbtrfs/dominic/git/ESCOMP/CTSM/cime/src/share/timing/gptl.c:4069:1: error: control reaches end of non-void function [-Werror=return-type]
from the following function. I believe that earlier versions of gcc only gives a warning rather than an error in this instance.
/*
** ncmp: compares values of memory adresses pointed to by a pointer. for use with qsort
*/
static int ncmp( const void *pa, const void *pb )
{
static const char *thisfunc = "GPTLsetoption";
const char** x = (const char**)pa;
const char** y = (const char**)pb;
if( *x > *y )
return 1;
if( *x < *y )
return -1;
if( *x == *y )
GPTLerror("%s: shared memory address between timers\n", thisfunc);
}
I expect this can be fixed by inserting a spurious return statement at the end of the function, but since I am interested to try to build an unmodified version of the code (I'm not currently a contributor on the project, so can't push changes upstream) I'm wondering if there's a workaround to convert this error to a warning using compiler flags?
As requested here is the gcc call that is genertaed by the makefile:
mpicc -c -I/run/media/dominic/hdbtrfs/dominic/git/ESCOMP
/CTSM/cime/src/share/timing -std=gnu99 -O -DCESMCOUPLED
-DFORTRANUNDERSCORE -DNO_R16 -DCPRGNU -DCESMCOUPLED
-DFORTRANUNDERSCORE -DNO_R16 -DCPRGNU -DNUOPC_INTERFACE
-DHAVE_MPI /run/media/dominic/hdbtrfs/dominic/git/ESCOMP
/CTSM/cime/src/share/timing/gptl.c
I'm wondering if there's a workaround to convert this error to a warning using compiler flags?
I would expect the -Wno-error option to have that effect. It should also be possible to narrow the scope of that to the specific diagnostic you report, but beware: there is no way with command-line options alone to narrow the effect to this particular instance of the issue.
Addendum
The question having been edited to show that the diagnostic category is return-type, I can say that one would use -Wno-error=return-type to make all diagnostics of this type warnings instead of errors.
-Werror elevates all warnings to errors. You can turn reverse this for specific warnings with -Wno-error=WarningName, such as -Wno-error=return-type, as is clearly documented in the GCC documentation for warning options:
This switch [-Werror=] takes a negative form, to be used to negate -Werror for specific warnings; for example -Wno-error=switch makes -Wswitch warnings not be errors, even when -Werror is in effect.
I would like to have compiler throw an error every time there is a declaration after statement because that is the coding style I want to enforce, but I also want to compile with -std=c99 since I use some of the specific c99 features.
The problem is that in c99 declarations are allowed anywhere in the code, not just at the beginning of a block.
Take a look at the following program:
// prog.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
int i = 0;
return 0;
}
If I compile this code with gcc like this:
gcc -std=c99 -Werror=declaration-after-statement prog.c
it throws the following error:
prog.c: In function ‘main’:
prog.c:6:9: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
6 | int i = 0;
| ^~~
cc1: some warnings being treated as errors
This is the behavior I would like to have when compiling with clang, but clang behaves differently.
If I compile the same code with clang like this:
clang -std=c99 -Werror=declaration-after-statement prog.c
it throws no errors.
Only if I compile the code with clang like this it throws the error I want:
clang -std=c90 -Werror=declaration-after-statement prog.c
prog.c:6:6: error: ISO C90 forbids mixing declarations and code [-Werror,-Wdeclaration-after-statement]
int i = 0;
^
1 error generated.
But this is not good for me because I need to use -std=c99.
Is it possible to force -Werror=declaration-after-statement along with -std=c99 when compiling with clang?
Looking at the source code of clang it seems like not supported.
The diagnostic is defined in clang/include/clang/Basic/DiagnosticSemaKind.td
def ext_mixed_decls_code : Extension<
"ISO C90 forbids mixing declarations and code">,
InGroup<DiagGroup<"declaration-after-statement">>;
And its only usage is in clang/lib/Sema/SemaStmt.cpp
StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
// Note that __extension__ can be around a decl.
unsigned i = 0;
// Skip over all declarations.
for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
// We found the end of the list or a statement. Scan for another declstmt.
for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
if (i != NumElts) {
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
Diag(D->getLocation(), diag::ext_mixed_decls_code); // <-- here
}
}
...
Note the !getLangOpts().C99 in the if. The diagnose code will never execute with a standard above c90.
Well one thing you can surely try is build clang by yourself and delete that part of the if so end up with if (!getLangOpts().CPlusPlus).
I tried and it worked for me.
You can configure the clang build with cmake -G "Ninja" -DCMAKE_BUILD_TYPE="Release" -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_C_COMPILER="/usr/bin/gcc" -DCMAKE_CXX_COMPILER="/usr/bin/g++" -DLLVM_PARALLEL_LINK_JOBS=2 -DLLVM_OPTIMIZED_TABLEGEN=ON path/to/llvm-project/llvm
I'm searching for a compiler flag for gcc and if possible for clang and the Microsoft compilers as well, that triggers a warning (error with -Werror) if a non-void function is called without using the return value like this:
int test() {
return 4;
}
int main(void) {
test(); //should trigger a warning
int number = test(); //shouldn't trigger the warning
return 0;
}
If there is no such compiler flag, maybe some way to tell the clang static analyzer to complain about it.
EDIT: To clarify my original question: I actually meant using the return value, not only assigning it.
I never used it myself (do you really need it?), you can try
defining the function with warn_unused_result attribute
enabling -Wunused-result flag with gcc.
This will tell you about any unused value from the function return.
In case, any doubts, SEE IT LIVE or SEE IT LIVE AGAIN Thanks to M.M for the link in the comment
Or:
#include <stdio.h>
extern int func1(void) __attribute__((warn_unused_result));
extern int func2(void);
int main(void)
{
func1();
int rc1 = func1();
int rc2 = func1();
func2();
printf("%d\n", rc1);
return 0;
}
Compilation (GCC 5.1.0 on Mac OS X 10.10.5):
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -c warn.c
warn.c: In function ‘main’:
warn.c:10:9: error: unused variable ‘rc2’ [-Werror=unused-variable]
int rc2 = func1();
^
warn.c:8:5: error: ignoring return value of ‘func1’, declared with attribute warn_unused_result [-Werror=unused-result]
func1();
^
cc1: all warnings being treated as errors
$
Some static code analyzers like splint can check for these kind of things:
$ splint check.c
Splint 3.1.2 --- 03 May 2009
check.c: (in function main)
check.c:6:5: Return value (type int) ignored: test()
Result returned by function call is not used. If this is intended, can cast
result to (void) to eliminate message. (Use -retvalint to inhibit warning)
Unlike #Sourav's answer, this does not require a specific __attribute__ annotation on the target function, but on the other hand possibly emits many warnings. Its usually possible to suppress the warnings for specific functions or function calls by using annotations (like /*#alt void#*/).
We want to start using -Wall -Werror on a large project.
Due to the size, this change has to be phased, and we want to start with the most important warnings first.
The best way to do it seems to be using -Wall -Werror, with exceptions for specific warnings. The exceptional warnings are those which we have a lot of (so fixing them all is hard and risky), and we don't consider them very dangerous.
I'm not saying we don't want to fix all these warnings - just not on the first phase.
I know two ways to exclude a warning from -Werror - the best is -Wno-error=xxx, and if it doesn't work - -Wno-xxx (of course, we prefer to see the warning and ignore it, rather than hide it).
My problem is with warnings which are enabled by default, and don't have a -Wxxx flag related to them. I couldn't find any way to alllow them when -Werror is used.
I'm specifically concerned about two specific warnings. Here's a program that exhibits them and the compiler output:
#include <stdio.h>
void f(int *p) { printf("%p\n", p); }
int main(int argc, char *argv[]) {
const int *p = NULL;
const unsigned int *q = NULL;
f(p); /* Line 7: p is const, f expects non const */
if (p == q) { /* Line 8: p is signed, q is unsigned */
printf("Both NULL\n");
}
return 0;
}
% gcc warn.c
warn.c: In function 'main':
warn.c:7: warning: passing argument 1 of 'f' discards qualifiers from pointer target type
warn.c:8: warning: comparison of distinct pointer types lacks a cast
I know the best solution is to fix these warnings, but it's much easier said than done. In order for this change to be successful, we have to do this phased, and can't do too many changes at once.
Any suggestions?
Thanks.
What about phasing on a compilation unit/module/library basis instead of per warning? Is triggering a subtarget compilation an option (a good-enough build system in place)?
It might be folly, but ...
Why not a simple grep ?
something like
gcc teste.c 2>&1 | grep -v 'comparison of distinct' | grep -v 'some_other_string'
You probably want to hide these greps in a script, and call the script from your makefile instead of gcc
According to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43245 it will be "-Wdiscarded-qualifiers", but since the bug-fixed entry is from May 1, 2014, the gcc compiler you are using might not support it.
In C, does initialising a variable to it's own value make sense? If yes, what for?
Allow me to elaborate. In Git sources there are some examples of initialising a variable to it's own undefined value, as seen in transport.c or wt-status.c. I removed assignments from those declarations and run tests. Seeing no regressions, I thought that those assignments were redundant.
On the other hand, I did some simple tests with GCC 4.6 and Clang 2.9.
#include <stdio.h>
int main() {
printf("print to increase probability of registers being non-zero\n");
int status = status;
return printf("%i\n", status);
}
Compiling with -Wall -std=c99 and various -O levels prints no warnings and shows that status == 0. Clang with a non-zero optimisation level prints some garbage values though. It makes me infer that results of such expressions are undefined.
I can imagine that such assignment can suppress an uninitialised variable warning, but it's not the case for the examples taken from Git. Removing assignments doesn't introduce any warnings.
Are such assignments an undefined behaviour? If not, what do you use them for?
I've suggested the change on the Git mailing list. Here's what I've learned.
This compiles because Standard C99 §6.2.1/7 says:
Any identifier that is not a structure, union, or enumeration tag "has scope that begins just after the completion of its declarator." The declarator is followed by the initializer.
However, value of status is Indeterminate. And you cannot rely on it being initialized to something meaningful.
How does it work?
int status creates an space for the variable to exist on the stack(local storage) which is then further read to perform status = status, status might get initialized to any value that was present in the stack frame.
How can you guard against such self Initialization?
gcc provides a specific setting to detect self Initializations and report them as errors:
-Werror=uninitialized -Winit-self
Why is it used in this code?
The only reason I can think it is being used in the said code is to suppress the unused variable warning for ex: In transport.c, if the control never goes inside the while loop then in that control flow cmp will be unused and the compiler must be generating a warning for it. Same scenario seems to be with status variable in wt-status.c
For me the only reason of such self-assigning initialization is to avoid a warning.
In the case of your transport.c, I don't even understand why it is useful. I would have left cmp uninitialized.
My own habit (at least in C) is to initialize all the variables, usually to 0. The compiler will optimize unneeded initialization, and having all variables initialized makes debugging easier.
There is a case when I want a variable to remain uninitialized, and I might self-assign it: random seeds:
unsigned myseed = myseed;
srand(myseed);
On MacOS X 10.7.2, I tried this example - with the result shown...
$ cat x3.c
#include <stdio.h>
int status = -7;
int main()
{
printf("status = %d\n", status);
int status = status;
printf("status = %d\n", status);
return 0;
}
$ make x3
gcc -O -std=c99 -Wall -Wextra x3.c -o x3
$ ./x3
status = -7
status = 1787486824
$
The stack space where the local status in main() has been used by printf() so the self-initialization copies garbage around.
I think status = status doesn't change the value of status (compared to int status;). I think it is used to suppress the unused variable warning.