Possible clang compiler bug with thread_local in templates - c++

In my project I need separate thread-local storage for each instance of a data member. Because I ran into problems while implementing this functionality, I extracted a simplified version of the code into the following C++14 program:
#include <iostream>
#include <unordered_map>
#include <vector>
template<class T> class ThreadLocalMember
{
public:
T& local() { return store.map[this]; }
private:
struct Store
{
Store() { std::cout << "construct" << std::endl; }
~Store() { std::cout << "destruct" << std::endl; }
std::unordered_map<ThreadLocalMember<T>*, T> map;
};
static thread_local Store store;
};
template <class T> thread_local typename ThreadLocalMember<T>::Store ThreadLocalMember<T>::store;
int main()
{
ThreadLocalMember<int> counter;
std::cout << "point 1" << std::endl;
int result = counter.local();
std::cout << "point 2; result: " << result << std::endl;
return result;
}
The expected output is
point 1
construct
point 2; result: 0
destruct
However, when compiled with clang Apple LLVM version 9.1.0 (clang-902.0.39.1) on MacOS High Sierra 10.13.4 using
clang++ -std=c++14 -O3 ThreadLocalMember.cpp -o test
(or with -O1 or -O2) the output is:
point 1
Illegal instruction: 4
It seems that the constructor of the thread_local variable is never executed and the program crashes when the variable is first accessed.
The problem goes away when
the program is compiled without optimisation (which is not acceptable in production mode)
the template class is replaced by a regular class (a possible workaround but very annoying)
the thread_local keyword is removed in both places (but then the program no longer does what I need it to do when there are multiple threads)
The program also compiles and runs fine when using gcc 5.4.0 on Ubuntu 16, with or without optimisation flag.
Is there something wrong with my code, or am I looking at a clang compiler bug?

Related

Clang ignores `__attribute__((aligned))` when used with an alias template

For writing SIMD code, I'd like to use templates to generate vector types with certain alignment. However, clang seems to ignore the alignment attribute when used with an alias template instead of a type alias.
Consider this code (godbolt):
#include <iostream>
#include <cstdint>
template <typename T=void>
using TemplatedT __attribute__((aligned(8))) = uint32_t;
using ManualT __attribute__((aligned(8))) = uint32_t;
int main() {
std::cout << "alignof Template: " << alignof(TemplatedT<>) << std::endl;
std::cout << "alignof Manual: " << alignof(ManualT) << std::endl;
}
With gcc 12.2, both aliases have an alignment of 8, as I would expect.
With clang 15 and trunk, the templated alias has an alignment of 4, ignoring the attribute.
Is this a bug? I looked through the open llvm issues but couldn't find a matching one.
Is there any workaround I can use?
Edit: As #HolyBlackCat proposed in the comments, extracting the templating to a wrapping struct seems to be a workaround:
template<typename ScalarT>
struct Vec {
using T __attribute__((aligned(8))) = ScalarT;
};
// and then use Vec<uint32_t>::T
Edit2:
I've opened an issue with the LLVM project at https://github.com/llvm/llvm-project/issues/59788.

Is Undefined Behavior To Using Invalid Iterator?

Consider this code:
#include <iostream>
#include <string>
#include <map>
int main()
{
std::map<std::string, std::string> map = {
{ "ghasem", "another" }
};
std::cout << map.find("another")->second << std::endl;
std::cout << map.size() << std::endl;
}
It will be compiled and run successfully(the process return value is 0), but we couldn't see the output of map.size(). Neither -fsanitize=address nor -fsanitize=undfined reports any problem. I compiled with GCC-11.2.1 and Clang-13.0.0, both are the same. And running the code step by step using GDB-11.1-5 will not help and all the steps will be run successfully.
But if I reorder the last two lines:
#include <iostream>
#include <string>
#include <map>
int main()
{
std::map<std::string, std::string> map = {
{ "ghasem", "another" }
};
std::cout << map.size() << std::endl;
std::cout << map.find("another")->second << std::endl;
}
I will get a Segmentation Fault and now ASAN could report the error.
And my question here is: Is the code cause some sort of Undefined Behavior? How could I detect those errors?
Environment:
OS: Fedora 35
Compiler(s):
GCC 11.2.1
Clang 13.0.0
Additional Compiler Flags:
Debugger: GDB 11.1-5
There is no key comparing equal to "another" in the map. Therefore map.find("another") will return the .end() iterator of the map. Dereferencing this iterator in ->second is then undefined behavior since end iterators may not be dereferenced.
Your code should check that the iterator returned from find is not the end iterator, i.e. that an element has been found.
In terms of debugging, if you are using libstdc++ as standard library implementation (which is the case with GCC and potentially with Clang), you can use -D_GLIBCXX_DEBUGon the compiler invocation to enable debug assertions in the standard library implementation which will detect this issue.

How to test different gcc target attributes

I've started using gcc target attributes and Intel intrinsics to make hardware specific implementations of certain functions. I'm unsure how to go about testing the different implementations easily. Given the example below, how can I, at either compile time or runtime, target/test the default case when executed on a machine that supports sse3?
#include <iostream>
__attribute__((target("default")))
void hello() {
std::cout << "Hello default wolrld" << std::endl;
}
__attribute__((target("sse3")))
void hello() {
std::cout << "Hello SSE3 world" << std::endl;
}
int main() {
hello();
}

lowest() is not a member of std::numeric_limits

I am trying to compile the following code:
#include <iostream>
#include <limits>
int main()
{
std::cout << std::numeric_limits<int>::lowest() << std::endl;
}
and I get the following error:
../main.cpp:5: error: 'lowest' is not a member of 'std::numeric_limits<int>'
cout << std::numeric_limits<int>::lowest() << std::endl;
^
I am using QT Creator 3.1.1 on Ubuntu 15.04, the compiler is set to GCC by default (/usr/bin/g++).
Anyone have an idea what could be the problem?
The lowest function was introduced in the C++11 standard, so you need to enable C++11 compatibility with the -std=c++11 flag (it's not enabled by default).

extended initializer lists being seen as functions

I'm trying to compile an opensource project but I'm getting this problem from g++
error: function definition does not declare parameters
the code is something like this
#include <iostream>
namespace hi {
class hello {
public:
bool first { true };
};
}
int main(int argc, char *argv[])
{
hi::hello h
std::cout << "output: " << h.first << std::endl;
return 0;
}
which produces the same compilation problem as the code of the opensource project when compiled with
g++ -O2 bools.cpp -o bools -std=c++0x
however if I try to compile this code with the same options it compiles and runs as it should
#include <iostream>
int main(int argc, char *argv[])
{
bool value { true };
std::cout << "output: " << value << std::endl;
return 0;
}
I'm using g++ 4.6.3 on Ubuntu 64bit.
thanks for your time.
Support for non-static data member initializers was added in gcc 4.7. You can see the list of what C++0x/C++11 features gcc supports with what versions here. The line for this feature says:
Non-static data member initializers | N2756 | GCC 4.7
This works perfectly fine in gcc 4.7 and greater, see it live here.