Is there any way show uninitialized variable being used? - c++

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

Related

Calling a function with uninitalized struct variable as a parameter doesn't produce a warning

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.

error: jump to label 'foo' crosses initialization of 'bar'

The following C++ example fails to compile with gcc or clang, but only generates a warning with ICC, and nothing at all with MSVC:
int main(int argc, char *argv[])
{
if (argc < 2)
goto clean_up;
#if 1 // FAIL
int i = 0;
#elif 0 // workaround - OK
{
int i = 0;
}
#else // workaround - OK
int i;
i = 0;
#endif
clean_up:
return 0;
}
g++:
init.cpp:13: error: jump to label ‘clean_up’
init.cpp:4: error: from here
init.cpp:7: error: crosses initialization of ‘int i’
clang++:
init.cpp:4:9: error: cannot jump from this goto statement to its label
goto clean_up;
^
init.cpp:7:9: note: jump bypasses variable initialization
int i = 0;
^
ICC:
init.cpp(4): warning #589: transfer of control bypasses initialization of:
variable "i" (declared at line 7)
goto clean_up;
^
I understand the cause of the error, and for a simple example such as this it is fairly easy to work around (I've included a couple of possible workarounds in the example above), but I'm working on a large cross-platform legacy code base that is peppered with error-handling macros which use a similar goto construct. Other developers working with MSVC or ICC keep introducing inline initialisations which subsequently result in errors for gcc or clang builds (and of course they just ignore the warnings they get with MSVC/ICC).
So I need to find a way to either (a) make such cases result in errors on ICC/MSVC or (b) reduce them to warnings with gcc/clang. I tried -fpermissive with gcc but that doesn't seem to help.
For extra credit I'm also curious as to the rationale behind this error for simple scalar initialisation - I can see why jumping over a constructor might be problematic, but initialising an int as in the above example doesn't seem like it could ever be an issue, and simply splitting the definition+initialisation into a definition + assignment makes the error go away?
The MSVC flag for treating a warning as en error is /we n where n is the number of the warning.
For example, /we4326 flags warning number C4326 as an error.
See https://msdn.microsoft.com/en-us/library/thxezb7y.aspx for details.

Clang (3.6.0) ignores warnings from included header files

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.

default initialization of aggregates

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]

Overkilling "crosses initialization of variable" error in C++?

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").