Commit: 862d08bb975740e3abf3a9a4dfbdcd48275d944c
Author: Jacques Lucke
Date:   Thu Jan 5 14:38:14 2023 +0100
Branches: master
https://developer.blender.org/rB862d08bb975740e3abf3a9a4dfbdcd48275d944c

Fix: use-after-free when threadlocal is destructed after static variable

This issue was introduced in rB78f28b55d39288926634d0cc.

The fix is to use a `std::shared_ptr` to ensure that the `Global` will live
long enough until all `Local` objects are destructed.

===================================================================

M       intern/guardedalloc/intern/memory_usage.cc

===================================================================

diff --git a/intern/guardedalloc/intern/memory_usage.cc 
b/intern/guardedalloc/intern/memory_usage.cc
index 71987ac38d9..bb557eeda97 100644
--- a/intern/guardedalloc/intern/memory_usage.cc
+++ b/intern/guardedalloc/intern/memory_usage.cc
@@ -4,6 +4,7 @@
 #include <atomic>
 #include <cassert>
 #include <iostream>
+#include <memory>
 #include <mutex>
 #include <vector>
 
@@ -14,10 +15,18 @@
 
 namespace {
 
+struct Local;
+struct Global;
+
 /**
  * This is stored per thread. Align to cache line size to avoid false sharing.
  */
 struct alignas(64) Local {
+  /**
+   * Retain shared ownership of #Global to make sure that it is not destructed.
+   */
+  std::shared_ptr<Global> global;
+
   /** Helps to find bugs during program shutdown. */
   bool destructed = false;
   /**
@@ -49,7 +58,8 @@ struct alignas(64) Local {
 };
 
 /**
- * This is a singleton that stores global data.
+ * This is a singleton that stores global data. It's owned by a 
`std::shared_ptr` which is owned by
+ * the static variable in #get_global_ptr and all #Local objects.
  */
 struct Global {
   /**
@@ -98,12 +108,17 @@ static std::atomic<bool> use_local_counters = true;
  */
 static constexpr int64_t peak_update_threshold = 1024 * 1024;
 
-static Global &get_global()
+static std::shared_ptr<Global> &get_global_ptr()
 {
-  static Global global;
+  static std::shared_ptr<Global> global = std::make_shared<Global>();
   return global;
 }
 
+static Global &get_global()
+{
+  return *get_global_ptr();
+}
+
 static Local &get_local_data()
 {
   static thread_local Local local;
@@ -113,28 +128,28 @@ static Local &get_local_data()
 
 Local::Local()
 {
-  Global &global = get_global();
-  std::lock_guard lock{global.locals_mutex};
+  this->global = get_global_ptr();
 
-  if (global.locals.empty()) {
+  std::lock_guard lock{this->global->locals_mutex};
+  if (this->global->locals.empty()) {
     /* This is the first thread creating #Local, it is therefore the main 
thread because it's
      * created through #memory_usage_init. */
     this->is_main = true;
   }
   /* Register self in the global list. */
-  global.locals.push_back(this);
+  this->global->locals.push_back(this);
 }
 
 Local::~Local()
 {
-  Global &global = get_global();
-  std::lock_guard lock{global.locals_mutex};
+  std::lock_guard lock{this->global->locals_mutex};
 
   /* Unregister self from the global list. */
-  global.locals.erase(std::find(global.locals.begin(), global.locals.end(), 
this));
+  this->global->locals.erase(
+      std::find(this->global->locals.begin(), this->global->locals.end(), 
this));
   /* Don't forget the memory counts stored locally. */
-  global.blocks_num_outside_locals.fetch_add(this->blocks_num, 
std::memory_order_relaxed);
-  global.mem_in_use_outside_locals.fetch_add(this->mem_in_use, 
std::memory_order_relaxed);
+  this->global->blocks_num_outside_locals.fetch_add(this->blocks_num, 
std::memory_order_relaxed);
+  this->global->mem_in_use_outside_locals.fetch_add(this->mem_in_use, 
std::memory_order_relaxed);
 
   if (this->is_main) {
     /* The main thread started shutting down. Use global counters from now on 
to avoid accessing

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to