Value initialized before main() disappears - c++

Can not understand weird program behavior - hopefully someone can explain.
dummy.h:
#ifndef DUMMY_H
#define DUMMY_H
#include <iostream>
class Dummy
{
int val;
public:
int Init(int new_val)
{
return val = new_val;
}
int Get()
{
return val;
}
Dummy():
val(-1)
{
std::cout << "constructed" << std::endl;
}
~Dummy()
{
std::cout << "deconstructed" << std::endl;
}
};
#endif /*DUMMY_H*/
header.h:
#include "dummy.h"
extern Dummy dummy;
dummy.cpp:
#include "dummy.h"
Dummy dummy;
main.cpp:
#include <iostream>
#include "header.h"
int res1 = dummy.Init(2);
int res2 = dummy.Get();
int main()
{
std::cout << res1 << std::endl;
std::cout << res2 << std::endl;
std::cout << dummy.Get() << std::endl;
return 0;
}
compiling: g++ -Wall -Wextra main.cpp dummy.cpp
output:
constructed
2
2
-1
deconstructed
why the 2nd Get(), called in main() function returns -1? Why the assigned value disappears from the dummy instance and no deconstructor was called. How it becomes -1?
upd: added debug info to Init() and Get():
new output:
init
get
constructed
2
2
get
-1
deconstructed
upd2: funny fact - separate compiling and linking object files in one executable changed the situation:
g++ -c dummy.cpp
g++ -c main.cpp
g++ dummy.o main.o
./a.out
constructed
init
get
2
2
get
2
deconstructed
but IT IS A TRAP!

The order of initialization of global variables in different translation units is unspecified. Either dummy or the two global ints in main.cpp could be constructed first.
In your case, it's res1 and res2 that got initialized first, so you invoked undefined behaviour by calling member functions on object that wasn't yet constructed.
To fix it, try this:
header.h:
#include "dummy.h"
Dummy& getDummy();
dummy.cpp:
#include "dummy.h"
Dummy& getDummy()
{
static Dummy dummy; // gets initialized at first call
// and persists for the duration of the program
return dummy;
}
main.cpp
int res1 = getDummy().Init(2);
int res2 = getDummy().Get();
If it helps understanding, add some debug cout statements to Get and Init, too.
What you experienced is also known as static initialization order fiasco.

So, what happens is that int res1 = dummy.Init(2); and int res2 = dummy.Get(); is run BEFORE dummy has been initialized. Then, before main is entered, dummy gets constructed and has the value -1 stored in val.
Yyou can possibly change this in this particular case, for this version of the compiler, by rearranging your object files to g++ -o myprog dummy.o main.o instead of g++ -o myprog main.o dummy.o - but that will not GUARANTEE to fix the problem, and in a future version of compiler/linker, the result may well alter again. The C++ standard gives no guarantee at all - I'm just suggesting the "order may matter" from what I've personally seen. And since there is no particular requirement for these things, the compiler vendor is allowed to change it in any which way they like at any time.

Related

Where is the syntax with class as a parameter in main needed?

This question states that main can be implementation defined with some restrictions.
So, I wrote the following C++ code to try out the following signature of main:
main.h
class MyClass {
private:
int i;
public:
MyClass();
inline int geti() {
return i;
}
inline void seti(int i) {
this->i = i;
}
~MyClass();
};
MyClass::MyClass() {
this->i = 2;
}
MyClass::~MyClass() {
}
main.c++
#include <iostream>
#include "main.h"
int main(MyClass myClass) {
std::cout << myClass.geti() << std::endl;
return 0;
}
Which Gives the following results:
The command g++ -o main main.c++ -O3 compiles successfully with warnings:
main.c++:5:5: warning: first argument of ‘int main(MyClass)’ should be ‘int’ [-Wmain]
5 | int main(MyClass myClass) {
| ^~~~
main.c++:5:5: warning: ‘int main(MyClass)’ takes only zero or two arguments [-Wmain]
The command clang++ -o main main.c++ -std=c++14 gives the error:
main.c++:5:5: error: first parameter of 'main' (argument count) must be of type 'int'
int main(MyClass myClass) {
^
1 error generated.
the main file generated by g++ gives SIGSEGV (why though?)
So, if main can be implementation defined, why does clang give an error while g++ generated file give SIGSEGV?
I also went further and created a different code so that I will be able to pass a MyClass object to main.c++ as follows:
#include <iostream>
#include "main.h"
#include <unistd.h>
int main() {
MyClass myClass;
execve("./main",myClass,NULL);
return 0;
}
However, as execve takes the second parameter to be a char* const *, it does not compile. How do I pass the myClass object to the main file generated by g++?
The command g++ -o main main.c++ -O3 compiles successfully with warnings
This is not successful compilation. You should always use -Werror. If you fail to do so and then decide to ignore the warning and proceed with running the program, it's your own responsibility. You better know full well what you are doing. See this for more information.
the main file generated by g++ gives SIGSEGV (why though?)
The compiler has warned you. It is in your best interest to listen to it. If things go boom, chances are, that's because you have ignored warnings.
why does clang give an error while g++ generated file give SIGSEGV?
The program is not a valid C++ program. There is no meaningful difference between a warning and an error.
How do I pass the myClass object to the main file generated by g++?
You cannot. main must have a form equivalent to one of these two:
int main()
int main(int argc, char* argv[])
(Optional reading in italics) Other forms of main are implementation-defined. This means your implementation needs to support them in a documented way. Unless you have read documentation for your implementation and found that it supports the form of main you want, there's no way to do that.
Other than having an implementation-defined main, the only way a program can get hold of an object of a class type is by constructing that object.
You are close. You have identified your primary issue attempting to pass as a parameter to main() -- that won't work. The declaration for main() is defined by the standard and you are limited to passing string values (nul-terminated character arrays... C-Strings) in as arguments.
In your case you need to create an instance of your class within main(), e.g.
#include <iostream>
#include "main.h"
int main() {
MyClass myClass;
std::cout << myClass.geti() << std::endl;
return 0;
}
Your main.h header has a variable shadowing problem where at line 10:
inline void seti(int i) {
int i shadows a prior declaration at line 3, e.g. int i; (though the consequence would be unlikely to matter). Just replace the variable name in the second declaration with j (or whatever you like). Your code will compile without warning, e.g.
class MyClass {
private:
int i;
public:
MyClass();
inline int geti() {
return i;
}
inline void seti(int j) {
this->i = j;
}
~MyClass();
};
MyClass::MyClass() {
this->i = 2;
}
MyClass::~MyClass() {
}
Example Use/Output
$ ./bin/main
2
You can also call your seti() function to update the private variable in your class, e.g.
myClass.seti(5);
std::cout << myClass.geti() << std::endl;
Which would now output 5.
Let me know if you have further questions.

Why is non-empty initialized static member std::string empty (in shared lib)?

Following is a simplification of code from a larger project:
// foo.h
#ifndef FOO_H
#define FOO_H
#include <string>
class Foo
{
public:
Foo( const std::string& s = magic_ );
void func();
static const std::string magic_;
private:
std::string s_;
};
void func( const std::string& s = Foo::magic_ );
#endif
//foo.cpp
#include "foo.h"
#include <iostream
const std::string Foo::magic_ = "please";
Foo::Foo( const std::string& s )
: s_( s )
{ }
void Foo::func() { std::cout << "[" << s_ << "]" << std::endl; }
void func( const std::string& s )
{
Foo( s ).func();
}
// main.cpp
#include "foo.h"
int main( int argc, char* argv[] )
{
func();
return 0;
}
I'll call the above a MCE, not a MCVE because unfortunately I've not been able to reproduce the problem in a simplification, which I can only guess is because of quirks of static variables and shared linkage - possibly an incorrect assessment, because of a not-thorough understanding of what's involved. But I will try to explain the problem. The following aspects of the above MCE are representative of the problem code:
A header file declares a class with a static member std::string.
The same header defines a function with an in-arg defaulted to the class' static member variable.
The header's corresponding source file defines the static member and function.
The translation unit is compiled to a shared library.
The executable's object code is linked with the shared library.
Compilation/output:
$ g++ -O3 -c -fPIC -o ./foo.o ./foo.cpp
$ g++ -O3 -shared ./foo.o -o ./libfoo.so
$ g++ -O3 -c -fPIE -o ./main.o ./main.cpp
$ g++ -O3 ./main.o -o ./a.out -L./ -lfoo
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH: ./a.out
[please]
Though not demonstrated above, is it a possibility that during executing the output may be "[]"? I.e. might Foo::magic_ be empty at the time used as the default value assigned to void func()'s in-arg?
This is hard to articulate in the absence of a demonstrable problem with the above MCE, but assuming it is truly representative of the problem code, I observe (by stdout due to gdb absence in the real build/test environment) that in void func(), in-arg s is an empty string - can anyone account for/explain why this could be?
I know initialization of static variables is not guaranteed across translation units - is that possibly involved here? (It seems like it might explain why the problem is not reproducible in an attempted simplification)
Again, apologies for the lack of a MCVE - I tried my best to create one.

C++ ld linker --wrap option does not work for internal function calls

I am trying to implement some unit tests for a C++ library that does not use OO (all functions are declared at namespace level)
For that purpose, I am trying to create a test binary that mocks (simulate) some functions.
I have achieved the above for functions that I call directly, but I have been unable to replace the calls that the library's functions do. The example below explains this:
Production code
Lets suppose this is the production code, the one that uses the real functions instead of the simulated ones:
CameraHandler.H
namespace Cam {
int myFunc();
int myFunc2();
}
CameraHandler.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc() {
// Imagine this is the function I want to simulate with a mock
// Its mangled name is _ZN3Cam6myFuncEv
return 1;
}
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
Testing code
This is the code for the unit testing. As you can see in the Makefile, it generates a binary called testsMain.
CameraHandlerMock.h
extern "C" {
int __wrap__ZN3Cam6myFuncEv(); // mangled name of Cam::myFunc(), with the __wrap_ prefix.
}
CameraHandlerMock.cpp
#include "CameraHandlerMock.h"
int __wrap__ZN3Cam6myFuncEv(){
// As you can see, the mocked function returns 999 instead of 1.
return 999;
}
UnitTestsMain.cpp
#include <iostream>
#include <typeinfo>
#include "CameraHandler.h"
#include "CameraHandlerMock.h"
extern "C" int _ZN3Cam6myFuncEv();
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
The Makefile
WRAP=-Wl,--wrap,_ZN3Cam6myFuncEv
all: production unitTests
production: // does not matter for this example
g++ main.cpp CameraHandler.cpp -o main
unitTests:
g++ ${WRAP} UnitTestsMain.cpp CameraHandlerMock.cpp CameraHandler.cpp -o testsMain
The problem
If I execute the testsMain program, I obtain the following result:
999 // call to Cam::myFunc()
12 // Cam::myFunc2(), which is Cam::myFunc() + 11.
Taking into account that Cam::myFunc2() calls to Cam::myFunc1(), and I have replaced it by __wrap__ZN3Cam6myFuncEv, what I expect is that t he result of calling Cam::myFunc2() is 999 + 11 = 1010. Nevertheless, Cam::myFunc2() is still calling the non-wrapped Cam::myFunc1(), so the result is 12.
Is there any way to wrap functions that are internally called by the library I want to test?
Let's lint a little bit of fluff first. In UnitTestsMain.cpp,
the declaration:
extern "C" int _ZN3Cam6myFuncEv();
is redundant. It simply instructs the C++ compiler that references to the function
of that prototype whose mangled name is _ZN3Cam6myFuncEv are references to
an externally defined function of that name. This is exactly the same information,
just expressed differently, that that the compiler has already got from:
namespace Cam {
int myFunc();
...
}
when it #include-ed CameraHandler.h, because _ZN3Cam6myFuncEv() is the mangled
form of Cam::myFunc. The extern "C" redeclaration of Cam::myFunc is harmless
but contributes nothing either to compilation or linkage.
On to the main question: Why does your mock
int __wrap__ZN3Cam6myFuncEv() get called instead of int Cam::myFunc in UnitTestsMain.cpp:
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
as you want; but your mock is not called for int Cam::myFunc in CameraHandler.cpp:
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
The answer lies in the documentation of the --wrap linker option:
--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to symbol will be
resolved to __wrap_symbol. Any undefined reference to __real_symbol will be
resolved to symbol.
Maybe you read it and didn't grok the significance of undefined reference.
This means that when --wrap=symbol is in effect, and the linker applies it
to an object file containing undefined references to symbol, it will replace them
with references to __wrap_symbol, and undefined references to __real_symbol,
in that object file, will be replaced with symbol.
Now in UnitTestsMain.o, compiled from UnitTestsMain.cpp, the references to both Cam::myFunc()
and Cam::myFunc2() are undefined. These functions are both defined in CameraHandler.cpp,
compiled in CameraHandler.o.
Therefore in the linkage of UnitTestsMain.o, --wrap ZN3Cam6myFuncEv will take effect and
replace the call to Cam::myFunc ( = ZN3Cam6myFuncEv) with a call to __wrap_ZN3Cam6myFuncEv.
The call to Cam::myFunc2() ( = ZN3Cam7myFunc2Ev) is not wrapped and is unaffected: it will be
resolved to the definition to be found in CameraHandler.o
But in the linkage of CameraHandler.o, both functions are defined, so --wrap has
no effect. When Cam::myFunc2() calls Cam::myFunc(), it calls ZN3Cam6myFuncEv, not
__wrap_ZN3Cam6myFuncEv.
That explains why the program outputs:
999
12
and not:
999
1010
Can you make your mocking work as expected?
Yes. You just have to ensure that every call to Cam::myFunc that you want to be
mocked is compiled into an object file that does not contain the (real) definition
of Cam::myFunc. The obvious way to do that is to define Cam::myFunc in its own
source file. Here's your example fixed:
CameraHandler.h
#ifndef CAMERAHANDLER_H
#define CAMERAHANDLER_H
namespace Cam {
int myFunc();
int myFunc2();
}
#endif
CameraHandlerMock.h
#ifndef CAMERAHANDLERMOCK_H
#define CAMERAHANDLERMOCK_H
extern "C" {
int __wrap__ZN3Cam6myFuncEv();
}
#endif
CameraHandler_myFunc.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc() {
return 1;
}
CameraHandler_myFunc2.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
CameraHandlerMock.cpp
#include "CameraHandlerMock.h"
int __wrap__ZN3Cam6myFuncEv() {
return 999;
}
UnitTestsMain.cpp
#include <iostream>
#include "CameraHandler.h"
#include "CameraHandlerMock.h"
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
Makefile
SRCS := UnitTestsMain.cpp CameraHandler_myFunc.cpp \
CameraHandler_myFunc2.cpp CameraHandlerMock.cpp
OBJS := $(SRCS:.cpp=.o)
LDFLAGS := -Wl,--wrap,_ZN3Cam6myFuncEv
.PHONY: unitTests clean
unitTests: testsMain
testsMain: $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
UnitTestsMain: CameraHandler.h CameraHandlerMock.h
CameraHandler_Func.o CameraHandler_Func2.o: CameraHandler.h
CameraHandlerMock.o: CameraHandlerMock.h
clean:
rm -f $(OBJS) testsMain
(Your production build is not considered at all in this example makefile)
With this, the test build runs like:
$ make
g++ -c -o UnitTestsMain.o UnitTestsMain.cpp
g++ -c -o CameraHandler_myFunc.o CameraHandler_myFunc.cpp
g++ -c -o CameraHandler_myFunc2.o CameraHandler_myFunc2.cpp
g++ -c -o CameraHandlerMock.o CameraHandlerMock.cpp
g++ -Wl,--wrap,_ZN3Cam6myFuncEv -o testsMain UnitTestsMain.o \
CameraHandler_myFunc.o CameraHandler_myFunc2.o CameraHandlerMock.o
and testsMain does what you expect:
$ ./testsMain
999
1010
You can simplify both source files and the makefile somewhat if you rewrite
CameraHandlerMock.cpp as just:
extern "C" {
int __wrap__ZN3Cam6myFuncEv() {
return 999;
}
}
Then you have no need for the mock header file CameraHandlerMock.h at all.
If you have a lot of functions you need to mock in this low-level way, it
may get tedious to define each one in its own source file. You may be aware
that there are higher-level, framework-supported mocking options, e.g. googlemock,
that have rich mocking capabilities and don't entail this tedium. It's fair to say, however, that they may
replace it with more complicated kinds of tedium.

GDB incomplete type when having C++ virtual function

I have just noticed something weird, when I add the "virtual keyword" in my class (any function except the constructor), I can't display the content of my object in GDB. GDB says "incomplete type"
Here is the code :
//////////////// reco.h /////////////
#ifndef RECO_H
#define RECO_H
#include <iostream>
#include <string>
class reco {
public:
reco(float weight);
~reco(void);
float getWeight();
private:
float weight;
};
#endif
///////////////// reco.cpp /////////////
#include <iostream>
#include <string>
#include "reco.h"
using namespace std;
reco::reco(float weight) {
weight = weight;
}
reco::~reco(void) {
cout << "destructor reco" << endl;
}
float reco::getWeight() {
return weight;
}
////////////// main.cpp /////////////
#include <iostream>
#include <string>
#include "reco.h"
using namespace std;
int main() {
reco* s = new reco(5.0);
cout << s->getWeight() << endl;
delete s;
return 0;
}
Then with GDB :
gdb main.exe
breakpoint main.cpp:11 <---- (cout)
run
print *s
$1 = { weight = 5 }
And then, if I make one of the functions "virtual", and I retry to print my *s pointer with GDB, it says:
"incomplete type"
It looks like there is something happening with the VTABLE, as if the "virtual" keyword was hiding the implementation of my Reco class. I know that the compiler does late binding and then, the VTABLE lookup is done at runtime, but the program is already running while GDB is debugging it, right ?
The "set print vtbl" setting in "on".
If I use ptype s, I get the <incomplete type> message again.
If I examine the address with x/540f80, it says "cannot access memory"
I don't know why just adding this keyword makes my object's type incomplete ?
Thanks a lot for your help !
One last thing that I notice :
WITH VIRTUAL:
reco.cpp -> g0 and main.cpp -> g = incomplete type
reco.cpp -> g and main.cpp ->g = ok
WITHOUT VIRTUAL
reco.cpp -> g0 and main.cpp -> g = ok
reco.cpp -> g and main.cpp ->g = ok
reco.cpp -> g and main.cpp ->g = ok
Assuming by -> g you mean that you compile reco.cpp with the -g flag, yes do that, and don't do this:
g++ -c -g0 reco.cpp
What you've discovered that is that GCC can optimize the amount on debug info it must emit if it knows that you have a key method.
Without virtual, there is no key method, and GCC must emit redundant debug info into every compilation unit. That makes your object files larger (it should have little or no effect on the final executable), but allows you to debug even when only some of your object files are compiled with debug info.

Const static variable defined in header file has same address in different translation unit

I have checked out the definition of std::ios::app in /usr/include/c++/4.6/bits/ios_base.h and found that std::ios::app is defined as a const static variable:
typedef _Ios_Openmode openmode;
/// Seek to end before each write.
static const openmode app = _S_app;
in which _Ios_Openmode is defined in the same header file as
enum _Ios_Openmode
{
_S_app = 1L << 0,
_S_ate = 1L << 1,
_S_bin = 1L << 2,
_S_in = 1L << 3,
_S_out = 1L << 4,
_S_trunc = 1L << 5,
_S_ios_openmode_end = 1L << 16
};
It's well known that static variable has internal linkage and every translation unit has its own
copy of this static variable, which means static variables in different translation unit should have different addresses. However, I have used two separate programs to print address of std::ios::app and found that the printed address are the same:
source file test1.cpp
#include <iostream>
int main() {
std::cout << "address: " << &std::ios::app << std::endl;
return 0;
}
result
address: 0x804a0cc
source file test2.cpp is the same with test1.cpp and the result is the same:
address: 0x804a0cc
This really confused me, shouldn't static variables in different translation units have different addresses?
Update: as is pointed out in the comments, std::ios::app is a static data member rather than a static const variable; static data member has external linkage and addresses of static data member in different translation unit should be the same. The second point is that my method for validating this fact is wrong: different program does not mean different translation unit.
Your test1.cpp and test2.cpp are not only two separate translation units, but you compile them into two entirely different programs and run them as separate processes. The memory space for each process is defined by the operating system anew each time you run it, and the absolute values of the addresses in each process cannot be compared. They may be identical even when you run the processes in parallel, because these addresses are interpreted relative to the virtual address space of each process. (*)
If you want to see the effect of internal linkage, you need to link the two translation units together after compiling them.
You can do this in the following way:
Define a header test.h:
const static int i = 0;
Define the implementation of a function print_i_1 in test1.cpp:
#include <iostream>
#include "test.h"
void print_i_1()
{ std::cout << &i << std::endl; }
Define the implementation of a function print_i_2 in test2.cpp:
#include <iostream>
#include "test.h"
void print_i_2()
{ std::cout << &i << std::endl; }
Note that both functions perform the same operation, but as long as they are compiled separately, they will each refer to a different instance of i.
Note also that none of these programs includes the definition of main(). We provide this in a third file, test.cpp:
extern void print_i_1();
extern void print_i_2();
int main()
{
print_i_1();
print_i_2();
return 0;
}
And now you compile each .cpp file (so we have three translation units). I am using GCC, but a similar thing is possible with other compilers, too:
g++ -W -Wall -g -o test1.o -c ./test1.cpp
g++ -W -Wall -g -o test2.o -c ./test2.cpp
g++ -W -Wall -g -o test.o -c ./test.cpp
And then link them together:
g++ -W -Wall -g -o test ./test.o ./test1.o ./test2.o
The output I get when running the resulting executable, test, is:
0x4009c8
0x4009d0
Two different addresses.
Note that the keyword static is not actually required in C++ to accomplish this for const variables in namespace scope (including global namespace scope). They have internal linkage automatically, unless explicitly declared extern.
(*) As it turns out, you seem to be using the address of a static member of a class defined in the standard library. In that case, there are two remarks to be made:
If you link to the standard library dynamically, objects can actually be shared even between two separate processes (which, however, still does not necessarily mean that the addresses displayed will be the same, due to each process still having its own address space);
However, static class members have external linkage, so your assumptions would have been wrong right from the start in this case.
9.4.2 defines the rules for static data members:
9.4.2/3 defines that a static const literal `can specify a brace-or-equal-initializer.' Meaning, that you can define it similar to X::x below.
9.4.2/4 defines that only one definition can exist (`one definition rule' (odr), see 3.2).
And finally, 9.4.2/5 further defines that all static data members of a class in namespace scope will have external linkage.
Example:
// test.h
struct X {
static const int x = 10;
};
// main.cpp
#include <iostream>
#include "test.h"
void f();
int main(int argc, const char* argv[]) {
std::cout << &X::x << std::endl;
f();
return 0;
}
// test.cpp
#include <iostream>
#include "test.h"
void f() {
std::cout << &X::x << std::endl;
}
Output:
001A31C4
001A31C4