Why won't gcc compile uninitialized global const? - gcc

When I try to compile the following with g++:
const int zero;
int main()
{
return 0;
}
I get an error about an uninitialized const 'zero'. I thought that global variables were default initialized to 0 [1] ? Why isn't this the case here?
VS compiles this fine.
[1] For example, see https://stackoverflow.com/a/10927293/331785

My gcc is slightly more verbose:
$ g++ zeroconst.c
zeroconst.c:1:11: error: uninitialized const ‘zero’ [-fpermissive]
We see that -fpermissive option will allow this to compile.
See this question on uninitialized const for a reference to C++ standard (the problem is C++-specific).
As cited at GCC wiki:
As mandated by the C++ standard (8.5 [decl.init], para 9 in C++03,
para 6 in C++0x), G++ does not allows objects of const-qualified type
to be default initialized unless the type has a user-declared default
constructor. Code that fails to compile can be fixed by providing an
initializer...

G++ requires that you initialize your constant during definition.

Related

KLEE does not find uninitialized variable error

I am learning KLEE now and I wrote a simple code:
#include "klee/klee.h"
#include <stdio.h>
#include <stdlib.h>
int test(int *p)
{
int *q = (int *) malloc(sizeof(int));
if ((*p) == (*q)) {
printf("reading uninitialized heap memory");
}
return 0;
}
int main()
{
int *p = (int *) malloc(sizeof(int));
test(p);
return 0;
}
First, I generate LLVM bitcode, and then I execute KLEE to the bitcode.
Following is all output:
KLEE: output directory is "/Users/yjy/WorkSpace/Test/klee-out-13"
Using STP solver backend
KLEE: WARNING: undefined reference to function: printf
KLEE: WARNING ONCE: calling external: printf(140351601907424)
reading uninitialized heap memory
KLEE: done: total instructions = 61
KLEE: done: completed paths = 4
KLEE: done: generated tests = 4
I suppose that KLEE should give me an error that the q pointer is not initialized, but it doesn't. Why KLEE does not give me an error or warning about this? KLEE can not detect this error? Thanks in advance!
TLTR: KLEE has not implemented this feature. Clang can check this directly.
KLEE currently support add/sub/mul/div overflow checking. To use this feature, you have to compile the source code with clang -fsanitize=signed-integer-overflow or clang -fsanitize=unsigned-integer-overflow .
The idea is that a function call is inserted into the bytecode (e.g. __ubsan_handle_add_overflow) when you use the clang sanitizer. Then KLEE will handle the overflow checking once it meets the function call.
Clang support
MemorySanitizer, AddressSanitizer UndefinedBehaviorSanitizer. They are defined in projects/compiler-rt/lib directory. MemorySanitizer is the one you are looking for, which is a detector of uninitialized reads.
You can remove the KLEE function call and check with clang directly.
➜ ~ clang -g -fsanitize=memory st.cpp
➜ ~ ./a.out
==16031==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x490954 (/home/hailin/a.out+0x490954)
#1 0x7f21b72f382f (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#2 0x41a1d8 (/home/hailin/a.out+0x41a1d8)
SUMMARY: MemorySanitizer: use-of-uninitialized-value (/home/hailin/a.out+0x490954)
Exiting

Initializing an `atomic_int` with a braced constant: Is this valid C code? If so why does it not compile in clang?

I'm porting some code from C11 to C++. The project compiles fine in gcc and g++ but clang refuses to compile it. The offending lines are shown below:
static atomic_int sem = {0};
src/testdir.c:27:25: error: illegal initializer type 'atomic_int'
(aka '_Atomic(int)')
and
struct container {
volatile atomic_ullong workerThreadCount;
struct cfgoptions *config;
repaircmd_t *cmd;
};
Container container = {{0}, s, NULL};
src/testdir.c:334:25: error: illegal initializer type 'volatile atomic_ullong'
(aka 'volatile _Atomic(unsigned long long)')
Clang:
clang version 3.7.0 (tags/RELEASE_370/final)
gcc:
gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
Operating system:
Fedora 23
Test code:
https://gist.github.com/clockley/eb42964003a2e4fe6de97d5b192d61d3
P.S i = {0} or i(0) are the only valid initializers in C++ as atomic ints are not primitive types of the two only the former is valid C.
I believe this is a bug in clang.
Here's a simple test case, with the result of compiling it with gcc and clang:
$ cat c.c
static _Atomic int x = ( 42 );
static _Atomic int y = { 42 };
$ gcc-6.1.0 -std=c11 -c c.c
$ clang-3.7 -std=c11 -c c.c
c.c:2:24: error: illegal initializer type '_Atomic(int)'
static _Atomic int y = { 42 };
^
1 error generated.
$
C explicitly permits the initializer for a scalar object to be enclosed in braces (N1570 6.7.9p11). I see nothing that forbids such an initializer for an atomic object.
Atomics are an optional feature in C11, but both gcc and clang support it (neither predefines __STDC_NO_ATOMICS__).
As a workaround, I suggest just dropping the braces. This:
static _Atomic int z = 42;
is valid and accepted by both compilers.
If you're need the code to compile both as C and as C++, then you might want to reconsider that requirement. But if it's really necessary, you can use the __cplusplus predefined macro to distinguish between C and C++ compilers:
static _Atomic int foo =
#ifdef __cplusplus
{ 42 };
#else
42;
#endif
or play some other tricks with macros.
(I'll note that C11's <stdatomic.h> header defines a macro ATOMIC_VAR_INIT that's intended to be used to initialize atomic objects, with an example:
atomic_int guide = ATOMIC_VAR_INIT(42);
It appears to be needed for atomic objects with automatic storage duration, which doesn't apply here.)
I must disagree strongly with Mad Physicist. The braces {} are used to initialize an aggregate. A single int is not an aggregate. You may put the initializer in () if you like, but {} are verboten. It would be an aggregate if you dimensioned it out to one entry, as in:
static atomic_int sem[ 1 ] = { 0 };
or even
static atomic_int sem[] = { 0 };
if you're too lazy to count one integer initializer!

Why do I get "warning: missing initializer for member"? [-Wmissing-field-initializers]?

Why am I getting a warning about initialization in one case, but not the other? The code is in a C++ source file, and I am using GCC 4.7 with -std=c++11.
struct sigaction old_handler, new_handler;
The above doesn't produce any warnings with -Wall and -Wextra.
struct sigaction old_handler={}, new_handler={};
struct sigaction old_handler={0}, new_handler={0};
The above produces warnings:
warning: missing initializer for member ‘sigaction::__sigaction_handler’ [-Wmissing-field-initializers]
warning: missing initializer for member ‘sigaction::sa_mask’ [-Wmissing-field-initializers]
warning: missing initializer for member ‘sigaction::sa_flags’ [-Wmissing-field-initializers]
warning: missing initializer for member ‘sigaction::sa_restorer’ [-Wmissing-field-initializers]
I've read through How should I properly initialize a C struct from C++?, Why is the compiler throwing this warning: "missing initializer"? Isn't the structure initialized?, and bug reports like Bug 36750. Summary: -Wmissing-field-initializers relaxation request. I don't understand why the uninitialized struct is not generating a warning, while the initialized struct is generating a warning.
Why is the uninitialized structs not generating a warning; and why is the initialized structs generating a warning?
Here is a simple example:
#include <iostream>
struct S {
int a;
int b;
};
int main() {
S s { 1 }; // b will be automatically set to 0
// and that's probably(?) not what you want
std::cout<<"s.a = "<<s.a<<", s.b = "<<s.b<<std::endl;
}
It gives the warning:
missing.cpp: In function ‘int main()’:
missing.cpp:9:11: warning: missing initializer for member 'S::b' [-Wmissing-field-initializers]
The program prints:
s.a = 1, s.b = 0
The warning is just a reminder from the compiler that S has two members but you only explicitly initialized one of them, the other will be set to zero. If that's what you want, you can safely ignore that warning.
In such a simple example, it looks silly and annoying; if your struct has many members, then this warning can be helpful (catching bugs: miscounting the number of fields or typos).
Why is the uninitialized structs not generating a warning?
I guess it would simply generate too much warnings. After all, it is legal and it is only a bug if you use the uninitialized members. For example:
int main() {
S s;
std::cout<<"s.a = "<<s.a<<", s.b = "<<s.b<<std::endl;
}
missing.cpp: In function ‘int main()’:
missing.cpp:10:43: warning: ‘s.S::b’ is used uninitialized in this function [-Wuninitialized]
missing.cpp:10:26: warning: ‘s.S::a’ is used uninitialized in this function [-Wuninitialized]
Even though it did not warn me about the uninitialized members of s, it did warn me about using the uninitialized fields. All is fine.
Why is the initialized structs generating a warning?
It warns you only if you explicitly but partially initialize the fields. It is a reminder that the struct has more fields than you enumerated. In my opinion, it is questionable how useful this warning is: It can indeed generate too much false alarms. Well, it is not on by default for a reason...
That's a defective warning. You did initialize all the members, but you just didn't have the initializers for each member separately appear in the code.
Just ignore that warning if you know what you are doing. I regularly get such warnings too, and I'm upset regularly. But there's nothing I can do about it but to ignore it.
Why is the uninitialized struct not giving a warning? I don't know, but most probably that is because you didn't try to initialize anything. So GCC has no reason to believe that you made a mistake in doing the initialization.
You're solving the symptom but not the problem. Per my copy of "Advanced Programming in the UNIX Environment, Second Edition" in section 10.15:
Note that we must use sigemptyset() to initialize the sa_mask member of the structure. We're not guaranteed that act.sa_mask = 0 does the same thing.
So, yes, you can silence the warning, and no this isn't how you initialize a struct sigaction.
The compiler warns that all members are not initialized when you initialize the struct. There is nothing to warn about declaring an uninitialized struct. You should get the same warnings when you (partially) initialize the uninitialized structs.
struct sigaction old_handler, new_handler;
old_handler = {};
new_handler = {};
So, that's the difference. Your code that doesn't produce the warning is not an initialization at all. Why gcc warns about zero initialized struct at all is beyond me.
The only way to prevent that warning (or error, if you or your organization is treating warnings as errors (-Werror option)) is to memset() it to an init value. For example:
#include <stdio.h>
#include <memory.h>
typedef struct {
int a;
int b;
char c[12];
} testtype_t;
int main(int argc, char* argv[]) {
testtype_t type1;
memset(&type1, 0, sizeof(testtype_t));
printf("%d, %s, %d\n", argc, argv[0], type1.a);
return 0;
}
It is not very clean, however, it seems like that for GCC maintainers, there is only one way to initialize a struct and code beauty is not on top of their list.

Can GCC issue a warning when 0 is passed as an argument?

I have been told that you could add some special instruction to your code to make GCC issue a warning when it detects that 0 is being passed as an argument (which means, when it is possible at compile-time).
I have looked for it but haven’t been able to find it. Is this true?
There is a function attribute you can use to warn on null pointers:
void foo(void *data) __attribute__((nonnull));
int main(void)
{
foo(0);
return 0;
}
$ gcc -Wall -c t.c
t.c: In function ‘main’:
t.c:5:5: warning: null argument where non-null required (argument 1) [-Wnonnull]
I'm not aware of anything built-in to check for 0 for integer types though.
You might find something that suits your need in the various BUILD_BUG_* macros from the Linux kernel though. They're in include/linux/kernel.h. (Cross-referenced here.)

GCC Compile-time checking of constant function inputs

I want to use gcc to do some compile-time checking on function inputs if the compiler knows that they are constants.
I have a solution that very almost works, and as far as I can see, it should work.
Note: __builtin_constant_p(expression) is supposed to returns whether an expression is known to be a constant at compile time.
Assuming we want to check whether port<2 when calling uart(port), the following code should work:
#include <stdio.h>
void _uart(int port) {
printf("port is %d", port);
}
#define uart(port) \
static_assert(__builtin_constant_p(port)? port<2: 1, "parameter port must be < 2"); \
_uart(port)
int main(void) {
int x=1;
uart(x);
}
This works when calling uart(). Unfortunately, it doesn't quite work for non-constant x. For some reason static_assert can't handle the case where x is not a constant, even though in theory __builtin_constant_p() won't even pass it a constant. The error message I get is:
c:\>gcc a.cpp -std=c++0x -Os
a.cpp: In function 'int main()':
a.cpp:13: error: 'x' cannot appear in a constant-expression
Any ideas?
Your code works with g++ (GCC) 4.8.2.
- but not with optimization, as you correctly noted.
If only we could use
static_assert(__builtin_choose_expr(__builtin_constant_p(port), \
port<2, 1), "parameter port must be < 2")
- but unfortunately the __builtin_choose_expr construct is currently only available for C.
However, there is a C++ patch which sadly didn't make it into the release yet.
You can try the trick used in the Linux kernel:
What is ":-!!" in C code?
The (somewhat horrible) Linux kernel macro is less strict about what kinds of expressions are allowed in the parameter.

Resources