UB или не UB в конструкторе с атомиком
Есть у меня конструктор, но случилось раз такое... что компилился 100% краш на nullptr.
class sStaticUnorderedMap final
{
public:
sStaticUnorderedMap(std::atomic_bool& _isAvaiable, spin_lock& _spinLock) : isAvaiable(_isAvaiable),
spinLock(_spinLock)
{
spinLock.lock();
_size = 0;
memset(data, 0, MAX_N * (sizeof(T) + sizeof(K) + sizeof(H) + sizeof(B)));
for (int i = 0; i < MAX_N; i++)
{
*(reinterpret_cast<B*>(data + i * BLOCK_SZ + OFFSET_B)) = 0;
}
isAvaiable = true; // КРАШ ТУТ
spinLock.unlock();
}
//...
std::atomic_bool& isAvaiable;
spin_lock& spinLock;
}
std::atomic_bool memory_located_is(false);
spin_lock memory_located_lock;
sStaticUnorderedMap<uint64_t, uint64_t, 3000000> memory_located(memory_located_is, memory_located_lock);
Крашилось от того, что инициализация атомика ещё не произошла и был nullptr access. UB или MSVC решил, что слишком легко мне программируется? Кто виноват и что делать?
Весь код:
constexpr bool is_s_memory = false;
template <class K, class T, int MAX_N = 128>
class sStaticUnorderedMap final
{
public:
using B = std::size_t;
using H = std::size_t;
using S = std::size_t;
using value_type = std::pair<const K, T>;
static const S OFFSET_B = 0;
static const S OFFSET_H = sizeof(B);
static const S OFFSET_K = sizeof(B) + sizeof(H);
static const S OFFSET_T = sizeof(B) + sizeof(H) + sizeof(K);
static const S BLOCK_SZ = sizeof(B) + sizeof(H) + sizeof(K) + sizeof(T);
static const S S_NOTFOUND = -1;
sStaticUnorderedMap(std::atomic_bool& _isAvaiable, spin_lock& _spinLock) : isAvaiable(_isAvaiable),
spinLock(_spinLock)
{
spinLock.lock();
_size = 0;
memset(data, 0, MAX_N * (sizeof(T) + sizeof(K) + sizeof(H) + sizeof(B)));
for (int i = 0; i < MAX_N; i++)
{
*(reinterpret_cast<B*>(data + i * BLOCK_SZ + OFFSET_B)) = 0;
}
isAvaiable = true;
spinLock.unlock();
}
~sStaticUnorderedMap()
{
spinLock.lock();
isAvaiable = false;
for (int i = 0; i < MAX_N; i++)
{
if (*(reinterpret_cast<B*>(data + i * BLOCK_SZ + OFFSET_B)) == 1)
{
K& tableK = *(reinterpret_cast<K*>(data + i * BLOCK_SZ + OFFSET_K));
T& tableT = *(reinterpret_cast<T*>(data + i * BLOCK_SZ + OFFSET_T));
tableK.~K();
tableT.~T();
*(reinterpret_cast<B*>(data + i * BLOCK_SZ + OFFSET_B)) = 0;
}
}
_size = 0;
spinLock.unlock();
}
void insert(const K& k, const T& t)
{
insert(K(k), T(t));
}
void insert(K&& k, T&& t)
{
_size++;
if (_size >= MAX_N)
throw;
H hash = std::hash<K>()(k);
S pos = hash % MAX_N;
while (true)
{
if (*(reinterpret_cast<B*>(data + pos * BLOCK_SZ + OFFSET_B)) == 0)
{
*(reinterpret_cast<B*>(data + pos * BLOCK_SZ + OFFSET_B)) = 1;
*(reinterpret_cast<H*>(data + pos * BLOCK_SZ + OFFSET_H)) = hash;
new(reinterpret_cast<K*>(data + pos * BLOCK_SZ + OFFSET_K)) K(k);
new(reinterpret_cast<T*>(data + pos * BLOCK_SZ + OFFSET_T)) T(t);
return;
}
const H& tableH = *(reinterpret_cast<H*>(data + pos * BLOCK_SZ + OFFSET_H));
if (hash == tableH)
{
const K& tableK = *(reinterpret_cast<K*>(data + pos * BLOCK_SZ + OFFSET_K));
if (tableK == k)
{
T& tableT = *(reinterpret_cast<T*>(data + pos * BLOCK_SZ + OFFSET_T));
tableT = t;
}
}
pos = (pos + 1) % MAX_N;
}
}
S find(const K& k)
{
H hash = std::hash<K>()(k);
S pos = hash % MAX_N;
while (true)
{
if (*(reinterpret_cast<B*>(data + pos * BLOCK_SZ + OFFSET_B)) == 0)
{
return S_NOTFOUND;
}
const H& tableH = *(reinterpret_cast<H*>(data + pos * BLOCK_SZ + OFFSET_H));
if (hash == tableH)
{
const K& tableK = *(reinterpret_cast<K*>(data + pos * BLOCK_SZ + OFFSET_K));
if (tableK == k)
{
return pos;
}
}
pos = (pos + 1) % MAX_N;
}
}
bool posIsLess(S posDel, S s, S hashPos)
{
if (s < posDel)
{
return (hashPos > s) & (hashPos <= posDel);
}
return (hashPos > s) | (hashPos <= posDel);
}
B& linkPosB(S pos)
{
return *(reinterpret_cast<B*>(data + pos * BLOCK_SZ + OFFSET_B));
}
H& linkPosH(S pos)
{
return *(reinterpret_cast<H*>(data + pos * BLOCK_SZ + OFFSET_H));
}
K& linkPosK(S pos)
{
return *(reinterpret_cast<K*>(data + pos * BLOCK_SZ + OFFSET_K));
}
T& linkPosT(S pos)
{
return *(reinterpret_cast<T*>(data + pos * BLOCK_SZ + OFFSET_T));
}
void posErase_no_rec(S s)
{
S posDel = s;
while (true)
{
s = (s + 1) % MAX_N;
//End line elems
if (!linkPosB(s))
{
linkPosK(posDel).~K();
linkPosT(posDel).~T();
linkPosB(posDel) = 0;
return;
}
S hashPos = linkPosH(s) % MAX_N;
if (posIsLess(posDel, s, hashPos))
{
linkPosH(posDel) = std::move(linkPosH(s));
linkPosK(posDel) = std::move(linkPosK(s));
linkPosT(posDel) = std::move(linkPosT(s));
posDel = s;
}
}
}
bool erase(const K& k)
{
S posDel = find(k);
H hash = std::hash<K>()(k);
if (posDel == S_NOTFOUND)
{
return false;
}
S posMov = S_NOTFOUND;
S pos = (posDel + 1) % MAX_N;
while (true)
{
if (*(reinterpret_cast<B*>(data + pos * BLOCK_SZ + OFFSET_B)) == 0)
{
if (posMov != S_NOTFOUND)
{
K& tableMovK = *(reinterpret_cast<K*>(data + posMov * BLOCK_SZ + OFFSET_K));
T& tableMovT = *(reinterpret_cast<T*>(data + posMov * BLOCK_SZ + OFFSET_T));
B& tableMovB = *(reinterpret_cast<B*>(data + posMov * BLOCK_SZ + OFFSET_B));
K& tableK = *(reinterpret_cast<K*>(data + posDel * BLOCK_SZ + OFFSET_K));
T& tableT = *(reinterpret_cast<T*>(data + posDel * BLOCK_SZ + OFFSET_T));
tableK = std::move(tableMovK);
tableT = std::move(tableMovT);
posErase_no_rec(posMov);
}
else
{
//Simple single thing
K& tableK = *(reinterpret_cast<K*>(data + posDel * BLOCK_SZ + OFFSET_K));
T& tableT = *(reinterpret_cast<T*>(data + posDel * BLOCK_SZ + OFFSET_T));
B& tableB = *(reinterpret_cast<B*>(data + posDel * BLOCK_SZ + OFFSET_B));
posErase_no_rec(posDel);
}
_size--;
return true;
}
const H& tableH = *(reinterpret_cast<H*>(data + pos * BLOCK_SZ + OFFSET_H));
if (hash == tableH)
{
const K& tableK = *(reinterpret_cast<K*>(data + pos * BLOCK_SZ + OFFSET_K));
if (tableK == k)
{
posMov = pos;
}
}
pos = (pos + 1) % MAX_N;
}
}
std::string strCC(std::string s)
{
std::string res;
for (int i = 0; i < 4; i++)
{
if (i < s.size())
{
res += s[i];
}
else
{
res += ' ';
}
}
return res;
}
std::string to_str()
{
std::string str;
for (int i = 0; i < MAX_N; i++)
{
if (*(reinterpret_cast<B*>(data + i * BLOCK_SZ + OFFSET_B)) == 1)
{
const H& tableH = *(reinterpret_cast<H*>(data + i * BLOCK_SZ + OFFSET_H));
const K& tableK = *(reinterpret_cast<K*>(data + i * BLOCK_SZ + OFFSET_K));
const T& tableT = *(reinterpret_cast<T*>(data + i * BLOCK_SZ + OFFSET_T));
str += strCC(std::to_string(tableH % MAX_N));
}
else
{
str += " ";
}
str += "|";
}
return str;
}
S size()
{
return _size;
}
char data[MAX_N * (sizeof(T) + sizeof(K) + sizeof(H) + sizeof(B))];
S _size;
std::atomic_bool& isAvaiable;
spin_lock& spinLock;
};
std::atomic_bool memory_located_is(false);
spin_lock memory_located_lock;
sStaticUnorderedMap<uint64_t, uint64_t, 3000000> memory_located(memory_located_is, memory_located_lock);
//Wery dangerous code
void* operator new(std::size_t sz)
{
void* ptr = std::malloc(sz);
if (ptr)
{
if constexpr (is_s_memory)
{
memory_located_lock.lock();
//if (memory_located.size() > 40000) {
// std::puts("M");
//}
if (memory_located_is)
memory_located.insert(reinterpret_cast<uint64_t>(ptr), static_cast<uint64_t>(sz));
memory_located_lock.unlock();
}
return ptr;
}
throw;
}
void operator delete(void* ptr) noexcept
{
if constexpr (is_s_memory)
{
memory_located_lock.lock();
if (memory_located_is)
memory_located.erase(reinterpret_cast<uint64_t>(ptr));
memory_located_lock.unlock();
}
std::free(ptr);
}
std::unordered_map<uint64_t, uint64_t> getTable()
{
unordered_map<uint64_t, uint64_t> res;
using StaticTable = sStaticUnorderedMap<uint64_t, uint64_t, 3000000>;
std::atomic_bool memory_located_copy_is(false);
spin_lock memory_located_copy_lock;
StaticTable* pmemory_located_copy = new StaticTable(memory_located_copy_is, memory_located_copy_lock);
memory_located_lock.lock();
if (memory_located_is)
{
memcpy(&pmemory_located_copy->data, memory_located.data, sizeof(memory_located.data) * sizeof(char));
pmemory_located_copy->_size = memory_located._size;
}
memory_located_lock.unlock();
if (memory_located_is)
{
for (int i = 0; i < 3000000; i++)
{
if (*(reinterpret_cast<StaticTable::B*>(pmemory_located_copy->data + i * StaticTable::BLOCK_SZ + StaticTable
::OFFSET_B)) == 1)
{
const StaticTable::H& tableH = *(reinterpret_cast<StaticTable::H*>(pmemory_located_copy->data + i *
StaticTable::BLOCK_SZ + StaticTable::OFFSET_H));
uint64_t tableK = *(reinterpret_cast<uint64_t*>(pmemory_located_copy->data + i * StaticTable::BLOCK_SZ +
StaticTable::OFFSET_K));
uint64_t tableT = *(reinterpret_cast<uint64_t*>(pmemory_located_copy->data + i * StaticTable::BLOCK_SZ +
StaticTable::OFFSET_T));
res.insert({tableK, tableT});
}
}
}
delete pmemory_located_copy;
pmemory_located_copy = nullptr;
return res;
}