Daniel
Daniel

Reputation: 21

-O2 and -fPIC option in gcc

For performance optimization, I would like to make use of the reference of a string rather than its value. Depending on the compilation options, I obtain different results. The behavior is a bit unclear to me, and I do not know the actual gcc flag that causes that difference.

My code is

#include <string>
#include <iostream>

const std::string* test2(const std::string& in) {
   // Here I want to make use of the pointer &in
   // ...
   // it's returned only for demonstration purposes...
   return &in;
}

int main() {
   const std::string* t1 = test2("text");
   const std::string* t2 = test2("text");
   // only for demonstration, the cout is printed....
   std::cout<<"References are: "<<(t1==t2?"equivalent. ":"different. ")<<t1<<"\t"<<t2<<std::endl;
   return 0;
}

There are three compilation options:

gcc main.cc -o main -lstdc++ -O0 -fPIC && ./main 
gcc main.cc -o main -lstdc++ -O2 -fno-PIC && ./main 
gcc main.cc -o main -lstdc++ -O2 -fPIC && ./main 

The first two yield equivalent results (References are: different.), so the pointers are different, but the third one results in equivalent pointers (References are: equivalent.). Why does this happen, and which option do I have to add to the options -O2 -fPIC such that the pointers become again different? Since this code is embedded into a larger framework, I cannot drop the options -O2 or -fPIC.

Since I get the desired result with the option -O2 and also with -fPIC, but a different behavior if both flags are used together, the exact behavior of these flags is unclear to me.

I tried with gcc4.8 and gcc8.3.

Upvotes: 2

Views: 358

Answers (1)

rustyx
rustyx

Reputation: 85256

Both t1 and t2 are dangling pointers, they point to a temporary std::string which is already destroyed. The temporary std::string is constructed from the string literal during each call to test2("text") and lives until the end of the full-expression (the ;).

Their exact values depend on how the compiler (re-)uses stack space at a particular optimization level.

which option do I have to add to the options -O2 -fPIC such that the pointers become again different?

The code exhibits undefined behavior because it's illegal to compare invalid pointer values. Simply don't do this.

If we ignore the comparing part, then we end up with this version:

#include <string>
#include <iostream>

void test2(const std::string& in) {
   std::cout << "Address of in: " << (void*)&in << std::endl;
}

int main() {
   test2("text");
   test2("text");
}

Now this code is free from UB, and it will print either the same address or different addresses, depending on how the compiler re-uses stack space between function calls. There is no way to control this, but it's no problem because keeping track of addresses of temporaries is a bad idea to begin with.

You can try using const char* as the input argument instead, then no temporary will be created in a call test2("text"). But here again, whether or not two instances of "text" point to the same location is implementation-defined. Though GCC does coalesce identical string literals, so at least in GCC you should observe the behavior you're after.

Upvotes: 3

Related Questions