Fix race in background index-cache writing
authorTom Tromey <tom@tromey.com>
Fri, 24 Mar 2023 21:53:22 +0000 (15:53 -0600)
committerTom Tromey <tom@tromey.com>
Fri, 31 Mar 2023 14:40:11 +0000 (08:40 -0600)
Tom de Vries pointed out a bug in the index-cache background writer --
sometimes it will fail.  He also noted that it fails when the number
of worker threads is set to zero.  These turn out to be the same
problem -- the cache can't be written to until the per-BFD's
"index_table" member is set.

This patch avoids the race by rearranging the code slightly, to ensure
the cache cannot possibly be written before the member is set.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30261

gdb/dwarf2/cooked-index.c
gdb/dwarf2/cooked-index.h
gdb/dwarf2/read.c

index 900f13c7de9cda426b8397dd034a6e7c42870fee..1b1a16b1ae26e1736723b694046ee6cf0ccf9a35 100644 (file)
@@ -443,26 +443,32 @@ cooked_index_shard::wait (bool allow_quit) const
     m_future.wait ();
 }
 
-cooked_index::cooked_index (vec_type &&vec, dwarf2_per_bfd *per_bfd)
+cooked_index::cooked_index (vec_type &&vec)
   : m_vector (std::move (vec))
 {
   for (auto &idx : m_vector)
     idx->finalize ();
 
-  /* This must be set after all the finalization tasks have been
-     started, because it may call 'wait'.  */
-  m_write_future
-    = gdb::thread_pool::g_thread_pool->post_task ([this, per_bfd] ()
-      {
-       maybe_write_index (per_bfd);
-      });
-
   /* ACTIVE_VECTORS is not locked, and this assert ensures that this
      will be caught if ever moved to the background.  */
   gdb_assert (is_main_thread ());
   active_vectors.insert (this);
 }
 
+/* See cooked-index.h.  */
+
+void
+cooked_index::start_writing_index (dwarf2_per_bfd *per_bfd)
+{
+  /* This must be set after all the finalization tasks have been
+     started, because it may call 'wait'.  */
+  m_write_future
+    = gdb::thread_pool::g_thread_pool->post_task ([this, per_bfd] ()
+       {
+         maybe_write_index (per_bfd);
+       });
+}
+
 cooked_index::~cooked_index ()
 {
   /* The 'finalize' method may be run in a different thread.  If
index b16b87bbb0ec1509af9b9702aad6af9ebadb9b50..f2664929e521ffa66cdf16ee00dfeb020e1b5d31 100644 (file)
@@ -366,7 +366,7 @@ public:
      object.  */
   using vec_type = std::vector<std::unique_ptr<cooked_index_shard>>;
 
-  cooked_index (vec_type &&vec, dwarf2_per_bfd *per_bfd);
+  explicit cooked_index (vec_type &&vec);
   ~cooked_index () override;
   DISABLE_COPY_AND_ASSIGN (cooked_index);
 
@@ -429,6 +429,9 @@ public:
     m_write_future.wait ();
   }
 
+  /* Start writing to the index cache, if the user asked for this.  */
+  void start_writing_index (dwarf2_per_bfd *per_bfd);
+
 private:
 
   /* Maybe write the index to the index cache.  */
index b362dfddb0cf797fe3b0f8f5347a3a43b05bc27b..8f35b973f3e914b1f1ed3907206d3fbc1b00820a 100644 (file)
@@ -5147,9 +5147,13 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
   indexes.push_back (index_storage.release ());
   indexes.shrink_to_fit ();
 
-  cooked_index *vec = new cooked_index (std::move (indexes), per_bfd);
+  cooked_index *vec = new cooked_index (std::move (indexes));
   per_bfd->index_table.reset (vec);
 
+  /* Cannot start writing the index entry until after the
+     'index_table' member has been set.  */
+  vec->start_writing_index (per_bfd);
+
   const cooked_index_entry *main_entry = vec->get_main ();
   if (main_entry != nullptr)
     {