It seems that clang is ignoring warnings which occur in included header files:
// what.hpp
class What {
public:
What() {
int x = x;
}
};
// main.cpp
#include <iostream>
#include "what.hpp"
int main()
{
int y = y;
std::cout << "y is: " << y << std::endl;
What w;
}
Compiling this with g++ (4.9.2) gives:
$ g++ -dumpversion && g++ -Wall -Wextra main.cpp -o main
4.9.2
In file included from main.cpp:3:0:
what.hpp: In constructor ‘What::What()’:
what.hpp:5:17: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]
int x = x;
^
main.cpp: In function ‘int main()’:
main.cpp:5:13: warning: ‘y’ is used uninitialized in this function [-Wuninitialized]
int y = y;
Compiling the same thing with clang:
$ clang++ --version && clang++ -Wall -Wextra main.cpp -o main
Ubuntu clang version 3.6.0-2ubuntu1~trusty1 (tags/RELEASE_360/final) (based on LLVM 3.6.0)
Target: x86_64-pc-linux-gnu
Thread model: posix
main.cpp:5:13: warning: variable 'y' is uninitialized when used within its own initialization [-Wuninitialized]
int y = y;
~ ^
1 warning generated.
I'm not sure, If I'm using clang wrong or if this is indeed a bug?
Any hints? Thanks in advance.
This is not clang bug, the warning is being suppressed because x is subsequently unused, the bug report I cite below explains the rationale behind this behavior.
In this specific case it is considered a clang feature to not to produce this warning(Wuninitialized) if the variable is otherwise unused, although most will probably find this surprising behavior.
We can see the rationale from the following bug report: No uninitialized warning for self-initialization (e.g., int x = x):
Right, this is deliberate, and is considered to be a feature rather
than a bug. We suppress the warning on 'int x = x;' only in the case
where 'x' is otherwise unused.
It is mentioned in the bug report that self-intialization in this way is:
considered the canonical way to suppress "use of uninitialized
variable" warnings
This does not depend on whether the code in question is included from a header, I put together a live example that shows the warning does not show up when the code is all in one file.
Note, initializing a variable in this way:
int x = x;
is undefined behavior, for reference see:
Does initialization entail lvalue-to-rvalue conversion? Is int x = x; UB?
Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14?
So in general we can not have any expectations as to the result and the compiler is not obligated to issue a diagnostic although doing so can be helpful.
The lines in question are syntactically correct. Neither are particularly useful lines of code - both exhibit undefined behavior - but they're legal C++ code. As such, the compiler is not obligated to issue any diagnostic.
This is just a quality of implementation issue - the compiler isn't obligated to issue warnings in this case, but it's very helpful when it does. As to why clang happens to warn only for y and not for x, whereas gcc warns for both - I am not sure. It definitely has nothing to do with included header files (you can see for yourself by just defining What in main.cpp) and likely has to do with the fact that you're printing y and never reading from x again.
But you can't rely on complete accuracy with these warnings. When you get them, however, they're always worth paying attention to.
Related
Consider the following code:
#include <tuple>
struct A {
template <typename... Types> operator std::tuple<Types...>() {
int i = 0;
return std::tuple<Types...>{Types(i++)...};
}
};
struct B {
B(int i){};
};
int main() {
A a;
std::tuple<B, B> t{a};
}
It produces the following warnings in gcc
$ g++-12 main.cpp -std=c++20 -Wall
main.cpp: In instantiation of ‘A::operator std::tuple<_UTypes ...>() [with Types = {B, B}]’:
main.cpp:18:23: required from here
main.cpp:7:46: warning: operation on ‘i’ may be undefined [-Wsequence-point]
7 | return std::tuple<Types...>{Types(i++)...};
| ^
main.cpp:7:46: warning: operation on ‘i’ may be undefined [-Wsequence-point]
but not in clang:
clang++-14 main.cpp -std=c++20 -Wall
main.cpp:18:20: warning: unused variable 't' [-Wunused-variable]
std::tuple<B, B> t{a};
^
1 warning generated.
Why?
This may be related but the referenced gcc bug is already fixed. I have gcc --version gcc (Debian 12.2.0-9) 12.2.0.
The order of evaluation of elements in a braced-init-list is strictly left-to-right, already since C++11, and regardless of the context in which the syntax is used. See https://timsong-cpp.github.io/cppwp/n3337/dcl.decl#dcl.init.list-4.
So the warning is bogus. #Artyer linked this bug report for a false positive warning under the question, which probably covers your example as well.
As mentioned in the other bug report you linked, GCC had actual wrong code generation for similar cases in earlier versions though, so you might want to be careful when relying on this order.
I have the following code in c++:
#include <iostream>
typedef struct Pair{
int x;
int y;
}Pair;
void dumFun(Pair p){}
int main() {
Pair p;
if (0){
p = {1,2};
}
dumFun(p);
return 0;
}
When I compiled the code, I expected to get a warning for the line with dumFun(p) since I'm calling a function with an uninitialized variable.
What I actually want is that my Makefile will give me warning for uninitialized scalar variable issues that I see with the tool Coverity.
Tried to use flag -Wall and I thought it shows warnings for unused variables usage as this - but it doesn't.
Is there any flag to use on a Makefile that will show me warning for the line I wrote above?
You did not tell the compiler, but at least in Clang there is no warning that would catch this. -Weverything shows all possible warnings, and you can use it to find the specific parameter needed to trigger each warning. Demonstration with -Weverything shows no warnings.
I did not find a suitable parameter in GCC either.
int main()
{
int a = 10;
int b;
a = b;
}
Valgrind can not warn me that b is uninitialized.
Your compiler should warn you regaring the uninitialized variable. If it doesn't, maybe the warnings are turned off?
This is gcc (9.3.0) output (with -Wall -Wextra option) :
prog.cc: In function 'int main()':
prog.cc:3:9: warning: variable 'a' set but not used [-Wunused-but-set-variable]
3 | int a = 10;
| ^
prog.cc:5:7: warning: 'b' is used uninitialized in this function [-Wuninitialized]
5 | a = b;
| ~~^~~
and this clang (10.0.0):
prog.cc:5:9: warning: variable 'b' is uninitialized when used here [-Wuninitialized]
a = b;
^
prog.cc:4:10: note: initialize the variable 'b' to silence this warning
int b;
^
Compile it with -Wall flag
gcc a.c -Wall -o a
Valgrind will only output errors if there is some potential impact on the behaviour of your application. In this case it does not matter that b is uninitialized.
Valgrind is, however, tracking the state of the memory.
If you run
valgrind --vgdb-error=0 ./test_exe
Then open another terminal and follow the instructions that were printed by Valgrind in the 1st terminal, then you can run commands like
mo xb {addess of b} 4
See here for details.
Within the language, there is no way to check for indeterminate values.
In simple cases such as this, compilers can detect it and you can ask to be warned about them. See the manual of your compiler for available warning options.
Compilers also provide "sanitisers" which check for bugs at runtime and are not limited by the complexity of the program as much as the compiletime warnings are. For reads of indeterminate values, a memory sanitiser would be the choice. They don't catch everything though, and the ones I tested did not catch the bug in your program. They could detect it if the indeterminate value was used to control the flow of the program:
int a = 10;
int b;
if (b) // detected by memory sanitiser
b = a;
Visual Studio Community (free) warns:
error C4700: uninitialized local variable 'b' used
For the following program, I do not get a warning that uoff.Reg and s.i is used without initialization. gcc (with -Wextra) and clang (with -Weverything) both do not warn, as I expected.
#include<stdint.h>
typedef union {
uint32_t Reg;
struct {
uint16_t Cx;
uint16_t sf;
};
} tf;
typedef struct {
uint16_t i;
uint16_t j;
} st;
int bar(tf, tf);
int foo(tf t0, int32_t offset) {
tf uoff;
st s;
t0.Reg = uoff.Reg + s.i + (uint32_t)offset;
t0.sf = uoff.sf;
return bar(t0, uoff);
}
I'm wondering why I'm not getting any warning. Does standard (C/C++) say that aggregates with automatic storage are initialized (by default) to zero, or is it a compiler limitation?
I checked gcc, : http://coliru.stacked-crooked.com/a/f1b25f7f369fbdbc, and warnings does get generated
here is how it gets compiled:
g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
and output:
main.cpp:10:3: warning: ISO C++ prohibits anonymous structs [-Wpedantic]
};
^
main.cpp: In function 'int foo(tf, int32_t)':
main.cpp:23:21: warning: 'uoff.tf::Reg' is used uninitialized in this function -Wuninitialized]
t0.Reg = uoff.Reg + s.i + (uint32_t)offset;
^
main.cpp:23:21: warning: 's.st::i' is used uninitialized in this function -Wuninitialized]
/tmp/ccIy8fGt.o: In function `foo(tf, int)':
main.cpp:(.text+0xa): undefined reference to `bar(tf, tf)'
collect2: error: ld returned 1 exit status
In order to guarantee zero-initialization of POD aggregate data members, you need to value-initialize your instance. For example,
st s = st(); // C++03 and C++11
st s = {}; // C++03 and C++11
st s{}; // C++11
Compilers are not required to warn you about uninitializad variables. However, the minimal set of compilation flags needed to get a warning with g++ seem to be
-Wuninitialized -O2
In other words, it seems that without optimization, the warning disappears. It could be that in this case variables get zero initialized.
Does standard (C/C++) say that aggregates with automatic storage are
initialized (by default) to zero
No, it doesn't. Automatic variables are not initialized, their value is initially left undefined. Using them without initialization results in undefined behavior.
However, naturally, the standard doesn't require you to initialize variables, compilers are free to warn about this, but using an uninitialized variable is not a constraint violation, thus, implementations do not have to warn you.
No, the C-Standard does not require the compiler to generate code to initialise auto variables. Reading their value without prior initialisation provokes undefined behaviuor.
However, this code
int main(void)
{
int a;
int b = a;
b = b;
return 0;
}
compiled using gcc's option -Wall, gives:
main.c:4: warning: ‘a’ is used uninitialized in this function
[gcc (Debian 4.4.5-8) 4.4.5]
I noticed that g++ complain a bit too strictly about crossed initialization and I wonder why these false-positive errors could not be removed just by looking at the SSA form of the program while compiling.
Let me give a very simple example:
#include <cstdlib>
int main ()
{
goto end;
int i = 0; // unused variable declaration
end:
return EXIT_SUCCESS;
}
When compiled with g++ -Wall -Wextra -o example1 example1.cc (g++ 4.8.1), the compiler gives the following error message:
example1.cc: In function ‘int main()’:
example1.cc:10:2: error: jump to label ‘end’ [-fpermissive]
end:
^
example1.cc:6:8: error: from here [-fpermissive]
goto end;
^
example1.cc:8:7: error: crosses initialization of ‘int i’
int i = 0;
^
example1.cc:8:7: warning: unused variable ‘i’ [-Wunused-variable]
So, it will raise an error where there is actually no risk because the variable is unused (the compiler obviously has both information and cannot combine it to deduce that the error is a false-positive).
More strange, I hoped that LLVM was more efficient at analyzing a program. So, I tried clang++ (LLVM) on this simple example with clang++ -Wall -Wextra -o example1 example1.cc (clang++ 3.4). And, I got about the same error message:
example1.cc:8:7: warning: unused variable 'i' [-Wunused-variable]
int i = 0;
^
example1.cc:6:3: error: goto into protected scope
goto end;
^
example1.cc:8:7: note: jump bypasses variable initialization
int i = 0;
^
1 warning and 1 error generated.
So, I am pretty sure that I am missing something important here, a problem that make the detection of this false-positive harder than I though. But, I do not know what is it. Or maybe, the C++ specification specifically says that it must be like this.
If somebody has an idea, feel free to share !
Edit: I also compiled the exact same code in C (gcc or clang), and it went fine just with the warning about i being an unused variable. So, it reinforce the fact that this is more likely linked to the specification of C++ and not a problem detecting this issue at compile time.
There is nothing wrong with the compilers. Your code is ill-formed according to the standard.
In your particular case, the requirement of the standard may not be necessary and the jump could be allowed and the compiler could create valid code. However, this is only because the initialisation of the variable int i has no side effects.
You can make your code valid by simply enclosing the jumped section in its own scope:
#include <cstdlib>
int main ()
{
goto end;
{
int i = 0; // unused variable declaration
}
end:
// cannot use i here, as it's not defined.
return EXIT_SUCCESS;
}
This is disallowed because potentially you'd call destructors for objects that aren't properly constructed. Admittedly, int doesn't have constructor or destructor, but it's making it "fair" for all types of objects. And technically, something at label end: could be using i, and by making the rule strict, it prevents the machine having to check every single code-path (which becomes a "halting problem").