[BOLT] Fix concurrent hash table modification in the instrumentation runtime
authorMichał Chojnowski <michal.chojnowski@scylladb.com>
Thu, 7 Jul 2022 10:54:51 +0000 (13:54 +0300)
committerVladislav Khmelevsky <och95@yandex.ru>
Thu, 7 Jul 2022 11:27:29 +0000 (14:27 +0300)
`__bolt_instr_data_dump()` does not lock the hash tables when iterating
over them, so the iteration can happen concurrently with a modification
done in another thread, when the table is in an inconsistent state. This
also has been observed in practice, when it caused a segmentation fault.

We fix this by locking hash tables during iteration. This is done by taking
the lock in `forEachElement()`.
The only other site of iteration, `resetCounters()`, has been correctly
locking the table even before this patch. This patch removes its `Lock`
because the lock is now taken in the inner `forEachElement()`.

Reviewed By: maksfb, yota9

Differential Revision: https://reviews.llvm.org/D129089

bolt/runtime/instr.cpp

index 8dd84ff..1a8bcf5 100644 (file)
@@ -289,6 +289,7 @@ public:
   /// Traverses all elements in the table
   template <typename... Args>
   void forEachElement(void (*Callback)(MapEntry &, Args...), Args... args) {
+    Lock L(M);
     if (!TableRoot)
       return;
     return forEachElement(Callback, InitialSize, TableRoot, args...);
@@ -378,7 +379,6 @@ template <typename T> void resetIndCallCounter(T &Entry) {
 
 template <typename T, uint32_t X, uint32_t Y>
 void SimpleHashTable<T, X, Y>::resetCounters() {
-  Lock L(M);
   forEachElement(resetIndCallCounter);
 }