]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Do not allow access to return value of tasks that ended in exceptions.
authorWolfgang Bangerth <bangerth@colostate.edu>
Fri, 30 Jun 2023 17:42:30 +0000 (11:42 -0600)
committerWolfgang Bangerth <bangerth@colostate.edu>
Sun, 2 Jul 2023 02:38:35 +0000 (20:38 -0600)
include/deal.II/base/thread_management.h

index ef83e24438334075eae017610033222368687c7a..c6c37d99a8e96d1bc87d3b319c3bf97a6fafb62e 100644 (file)
@@ -218,18 +218,26 @@ namespace Threads
     struct return_value
     {
     private:
-      RT value;
+      RT   value;
+      bool value_is_initialized;
 
     public:
       using reference_type = RT &;
 
       inline return_value()
         : value()
+        , value_is_initialized(false)
       {}
 
       inline reference_type
       get()
       {
+        Assert(
+          value_is_initialized,
+          ExcMessage(
+            "You cannot read the return value of a thread or task "
+            "if that value has not been set. This happens, for example, if "
+            "a task or thread threw an exception."));
         return value;
       }
 
@@ -240,14 +248,19 @@ namespace Threads
       }
 
       /**
-       *  Set the value from the given `std::future` object. If the future
+       * Set the value from the given `std::future` object. If the future
        * object holds an exception, the set will not happen and this function
        * instead throws the exception stored in the future object.
        */
       inline void
       set_from(std::future<RT> &v)
       {
-        value = std::move(v.get());
+        // Get the value from the std::future object. If the future holds
+        // an exception, then the assignment fails, we exit the function via the
+        // exception right away, and value_is_initialized is not set to true --
+        // that's something we can check later on.
+        value                = std::move(v.get());
+        value_is_initialized = true;
       }
     };
 
@@ -275,18 +288,26 @@ namespace Threads
     struct return_value<RT &>
     {
     private:
-      RT *value;
+      RT * value;
+      bool value_is_initialized;
 
     public:
       using reference_type = RT &;
 
       inline return_value()
         : value(nullptr)
+        , value_is_initialized(false)
       {}
 
       inline reference_type
       get() const
       {
+        Assert(
+          value_is_initialized,
+          ExcMessage(
+            "You cannot read the return value of a thread or task "
+            "if that value has not been set. This happens, for example, if "
+            "a task or thread threw an exception."));
         return *value;
       }
 
@@ -304,7 +325,12 @@ namespace Threads
       inline void
       set_from(std::future<RT &> &v)
       {
-        value = &v.get();
+        // Get the value from the std::future object. If the future holds
+        // an exception, then the assignment fails, we exit the function via the
+        // exception right away, and value_is_initialized is not set to true --
+        // that's something we can check later on.
+        value                = &v.get();
+        value_is_initialized = true;
       }
     };
 

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.