Segmentation fault in capturing aligned variables in lambdas - c++

This little code snippet segfaults with g++ 6.2.0 and clang++ 3.8.1 with:
clang++ -std=c++11 -O3 -mavx -pthread or g++ -std=c++11 -O3 -mavx -pthread
#include <thread>
#include <iostream>
class alignas(32) AlignedObject {
public:
float dummy[8];
};
int main() {
while (true) {
std::thread([](){
AlignedObject x;
std::cout << &x;
std::thread([x](){
std::cout << &x;
}).join();
}).join();
}
return 0;
}
Looking at the disassembly, both compilers are inserting vmovaps instructions that are failing, suggesting that compiler-generated objects somewhere aren't being aligned properly. It works fine if -mavx is removed since the instruction doesn't get used anymore. Is this a compiler bug or is this code relying on undefined behaviour?

Alignment specifiers such as alignas(n) or __attribute__((aligned(n))) are observed only for variables with automatic storage class. However std::function (which is used by the lambda) is permitted (and sometimes required) to dynamically allocate the function closure, in which case alignment specifiers are ignored and only alignments up to std::max_align_t are guaranteed.
In conclusion, short of passing your own custom allocator to the underlying std::function, objects with extended alignment requirements cannot be safely captured by value in lambdas, and must be captured by reference. (I guess this is more a property of std::bind and not lambdas specifically).

Related

Why does g++ 11 trigger "maybe uninitialized" warning in connection with this pointer casting

After a compiler update from g++ v7.5 (Ubuntu 18.04) to v11.2 (Ubuntu 22.04), the following code triggers the maybe-uninitialized warning:
#include <cstdint>
void f(std::uint16_t v)
{
(void) v;
}
int main()
{
unsigned int pixel = 0;
std::uint16_t *f16p = reinterpret_cast<std::uint16_t*>(&pixel);
f(*f16p);
}
Compiling on Ubuntu 22.04, g++ v11.2 with -O3 -Wall -Werror.
The example code is a reduced form of a real use case, and its ugliness is not the issue here.
Since we have -Werror enabled, it leads to a build error, so I'm trying figure out how to deal with it right now. Is this an instance of this gcc bug, or is there an other explanation for the warning?
https://godbolt.org/z/baaMTxhae
You don't initialize an object of type std::uint16_t, so it is used uninitialized.
This error is suppressed by -fno-strict-aliasing, allowing pixel to be accessed through a uint16_t lvalue.
Note that -fstrict-aliasing is the default at -O2 or higher.
It could also be fixed with a may_alias pointer:
using aliasing_uint16_t = std::uint16_t [[gnu::may_alias]];
aliasing_uint16_t* f16p = reinterpret_cast<std::uint16_t*>(&pixel);
f(*f16p);
Or you can use std::start_lifetime_as:
static_assert(sizeof(int) >= sizeof(std::uint16_t) && alignof(int) >= alignof(std::uint16_t));
// (C++23, not implemented in g++11 or 12 yet)
auto *f16p = std::start_lifetime_as<std::uint16_t>(&pixel);
// (C++17)
auto *f16p = std::launder(reinterpret_cast<std::uint16_t*>(new (&pixel) char[sizeof(std::uint16_t)]));

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

How can I make GCC/Clang warn about the use of uninitialized members?

I am compiling the code behind
class Test {
public:
Test() {}
int k;
};
int main() {
Test t;
std::cout << t.k << "\n";
}
like
g/clang++ main.cpp -Wall -Wextra --std=c++14 -o exe; ./exe
Why neither of the compilers does not warn me about indeterminate value of the integer is not it a very serious potential bug? How to enable a warning for indeterminate initializations?
For this example, GCC gives me the desired warning when I give it -O1 (or higher).
Presumably whatever mechanism it uses to detect this is tied into the optimisation effort level somehow. It's a notoriously hard thing to do.
Ensure that you heed your release-build warnings as well as debug-build warnings.

Why is no 'unused variable' warning given for boost::scoped_lock instances? [duplicate]

boost::mutex::scoped_lock is a handy RAII wrapper around locking a mutex. I use a similar technique for something else: a RAII wrapper around asking a data interface to detach from/re-attach to a serial device.
What I can't figure out, though, is why in the code below only my object mst — whose instantiation and destruction do have side effects — causes g++ to emit an "unused variable" warning error whereas l manages to remain silent.
Do you know? Can you tell me?
[generic#sentinel ~]$ cat test.cpp
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
struct MyScopedThing;
struct MyWorkerObject {
void a() { std::cout << "a"; }
void b() { std::cout << "b"; }
boost::shared_ptr<MyScopedThing> getScopedThing();
};
struct MyScopedThing {
MyScopedThing(MyWorkerObject& w) : w(w) {
w.a();
}
~MyScopedThing() {
w.b();
}
MyWorkerObject& w;
};
boost::shared_ptr<MyScopedThing> MyWorkerObject::getScopedThing() {
return boost::shared_ptr<MyScopedThing>(new MyScopedThing(*this));
}
int main() {
boost::mutex m;
boost::mutex::scoped_lock l(m);
MyWorkerObject w;
const boost::shared_ptr<MyScopedThing>& mst = w.getScopedThing();
}
[generic#sentinel ~]$ g++ test.cpp -o test -lboost_thread -Wall
test.cpp: In function ‘int main()’:
test.cpp:33: warning: unused variable ‘mst’
[generic#sentinel ~]$ ./test
ab[generic#sentinel ~]$ g++ -v 2>&1 | grep version
gcc version 4.4.5 20110214 (Red Hat 4.4.5-6) (GCC)
Note that the question has changed since the other answers were written.
Likely the reason g++ doesn't warn in the current form is because mst is a reference, and constructing and destructing a reference has no side effects. It's true that here the reference is extending the lifetime of a temporary, which has effects in its constructor and destructor, but apparently g++ doesn't realise that makes a difference.
If my memory serves me right, g++ has the unfortunate habit of emitting unused variable errors differently depending on the optimization settings because the detection works at the optimizer level.
That is, the code is optimized in SSA form, and if the optimizer detects that a variable, after optimization, is unused, then it may emit a warning (I much prefer Clang analysis for this...).
Therefore it is probably a matter of detecting what the destructor does. I wonder if it takes a conservative approach whenever the definition of the destructor is offline, I would surmise this equates a function call then and that the this qualify as a use of the variable.
I suspect the reason is that your class has a trivial
destructor, and that g++ only warns about unused variables if
the destructor is trivial. Invoking a non-trivial destructor is a
"use".

Strict aliasing and std::array vs C-style array

When compiling the following code with gcc 4.7 (g++-mp-4.7 (GCC) 4.7.0 built with MacPorts on OS X) I get seemingly contradictory results.
The compiler does not complain when I try to reinterpret and dereference a section of an std::array as an uint32_t but it does when using a C-style array.
Example code:
#include <array>
#include <cstdint>
int main() {
std::array<uint8_t, 6> stdarr;
*reinterpret_cast<uint32_t*>(&stdarr[0]) = 0; // OK
uint8_t arr[6];
*reinterpret_cast<uint32_t*>(&arr[0]) = 0;
// ^ error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
}
Compiler command is:
$ g++ -o test -std=c++0x -Wall -Wextra -Werror main.cpp
Why are they treated differently?
When taking the address of the std::array, the expression arr[0] is equivalent to the function call arr.operator[](0) which returns a reference, rather than the pointer arithmetic expression (arr + 0). Perhaps the compiler does not attempt to "see through" the operator[] function call when generating aliasing warnings.