skarupke / flat_hash_map

A very fast hashtable
1.69k stars 186 forks source link

Usage of static data in empty_default_table causes issues across modules #43

Open amzeratul opened 2 years ago

amzeratul commented 2 years ago

These two pieces of code cause issues when the flat_hash_map is used across modules (e.g. being shared between a DLL and the executable, which is a common use case for me):

    static sherwood_v3_entry * empty_default_table()
    {
        static sherwood_v3_entry result[min_lookups] = { {}, {}, {}, {special_end_value} };
        return result;
    }
    void deallocate_data(EntryPointer begin, size_t num_slots_minus_one, int8_t max_lookups)
    {
        if (begin != Entry::empty_default_table())
        {
            AllocatorTraits::deallocate(*this, begin, num_slots_minus_one + max_lookups + 1);
        }
    }

This is because each module will have its own static empty default table, which will cause an issue with deallocation, corrupting the heap.

I assume there are other pathological cases, e.g. two threads could initialize that static at the same time, resulting in two hashtables with different defaults and eventually leading to a heap corruption.

I have successfully worked around the issue by tagging the first sherwood_v3_entry with a flag indicating its the default table, and checking for that instead, however this will cost one byte if T has alignment of 1 byte (otherwise it should occupy the padding space anyway). There might be a better solution, but I'm not familiar enough with the code to find it!

Here's a link to my changes on my own repo if they're of any use.