Repository navigation
Never destroy the DialectContext map - #146
Conversation
ContextMap::get() kept the map in a function-local static. A client that destroys its last DialectContext from another static destructor can run after the map has been destroyed, because statics are destroyed in reverse order of construction and the map is created lazily by the first DialectContext. ~DialectContext then calls ContextMap::remove() on a destroyed DenseMap, which probes freed buckets: it can loop forever or write into freed memory. Allocate the map once and never destroy it using a standard idiomatic approach to avoid "static destruction order fiasco". This change avoids using a heap allocation primarily to avoid analysis tools flagging a memory leak.
|
This looks quite dirty. A DialectContext creates the ContextMap in its constructor, so, just from that the destruction order should be guaranteed to be the correct one. Before we merge this, I’d like to understand why this is the best solution. |
Flakebi
left a comment
There was a problem hiding this comment.
Ok, so roughly what goes wrong is:
- A compiler is created in a static variable A
- At some point, the compiler is requested to compile something, creating a dialect (held in a member variable of the compiler) and the ContextMap in static B
At cleanup time, static B with the ContextMap is deleted first (as it destroys in reverse order),
then static A with the compiler is deleted, deleting the Dialect which then tries to access the already deleted ContextMap.
In short, the combination of multiple statics and lazy initialization causes the problem.
That seems like a pattern we should support, so LGTM.
ContextMap::get() kept the map in a function-local static. A client that destroys its last DialectContext from another static destructor can run after the map has been destroyed, because statics are destroyed in reverse order of construction and the map is created lazily by the first DialectContext. ~DialectContext then calls ContextMap::remove() on a destroyed DenseMap, which probes freed buckets: it can loop forever or write into freed memory.
Allocate the map once and never destroy it using a standard idiomatic approach to avoid "static destruction order fiasco". This change avoids using a heap allocation primarily to avoid analysis tools flagging a memory leak.