icc: make babl_space_from_icc threadsafe
authorØyvind Kolås <pippin@gimp.org>
Wed, 3 Feb 2021 00:08:27 +0000 (01:08 +0100)
committerØyvind Kolås <pippin@gimp.org>
Wed, 3 Feb 2021 00:11:22 +0000 (01:11 +0100)
When multiple threads concurrently try to use ICC profiles / spaces
races during construction could cause broken internal representation of
profiles.

babl/babl-icc.c
babl/babl-internal.c
babl/babl-internal.h

index 52a35d2a5a9b7c76d95829271eb09ed9e39f3b00..0bbb47e1df671e1f4345441227e483ab7b3534d1 100644 (file)
@@ -957,6 +957,8 @@ babl_space_from_icc (const char   *icc_data,
 
   sign_t profile_class, color_space, pcs;
 
+  babl_mutex_lock (babl_space_mutex);
+
   if (!error) error = &int_err;
   *error = NULL;
 
@@ -973,13 +975,22 @@ babl_space_from_icc (const char   *icc_data,
     {
        ret = _babl_space_for_lcms (icc_data, icc_length);
        if (!ret)
+       {
+         babl_mutex_unlock (babl_space_mutex);
          return NULL;
+       }
        if (ret->space.icc_type == BablICCTypeCMYK)
+       {
+         babl_mutex_unlock (babl_space_mutex);
          return ret;
+       }
        ret->space.icc_length = icc_length;
        ret->space.icc_profile = malloc (icc_length);
        if (!ret->space.icc_profile)
+       {
+         babl_mutex_unlock (babl_space_mutex);
          return NULL;
+       }
        memcpy (ret->space.icc_profile, icc_data, icc_length);
 
 #ifdef HAVE_LCMS
@@ -1010,6 +1021,7 @@ babl_space_from_icc (const char   *icc_data,
        cmsCloseProfile (ret->space.cmyk.lcms_profile); // XXX keep it open in case of CMYK to CMYK transforms needed?
 #endif
        ret->space.icc_type = BablICCTypeCMYK;
+       babl_mutex_unlock (babl_space_mutex);
        return ret;
     }
 
@@ -1113,6 +1125,7 @@ babl_space_from_icc (const char   *icc_data,
   {
 
     babl_free (state);
+    babl_mutex_unlock (babl_space_mutex);
     return NULL;
   }
 
@@ -1130,6 +1143,7 @@ babl_space_from_icc (const char   *icc_data,
     ret->space.icc_profile = malloc (icc_length);
     memcpy (ret->space.icc_profile, icc_data, icc_length);
     babl_free (state);
+    babl_mutex_unlock (babl_space_mutex);
     return ret;
 
 
@@ -1175,6 +1189,7 @@ babl_space_from_icc (const char   *icc_data,
            *error = "Inconsistent ICC profile detected, profile contains both cLUTs and a matrix with swapped primaries, this likely means it is an intentionally inconsistent Argyll profile is in use; this profile is only capable of high accuracy rendering and does not permit acceleration for interactive previews.";
            fprintf (stderr, "babl ICC warning: %s\n", *error);
            babl_free (state);
+           babl_mutex_unlock (babl_space_mutex);
            return NULL;
         }
       }
@@ -1184,6 +1199,7 @@ babl_space_from_icc (const char   *icc_data,
      if (ret)
      {
         babl_free (state);
+        babl_mutex_unlock (babl_space_mutex);
         return ret;
      }
 
@@ -1199,6 +1215,7 @@ babl_space_from_icc (const char   *icc_data,
        ret->space.icc_length  = icc_length;
        ret->space.icc_profile = malloc (icc_length);
        memcpy (ret->space.icc_profile, icc_data, icc_length);
+       babl_mutex_unlock (babl_space_mutex);
        return ret;
      }
   }
@@ -1216,11 +1233,13 @@ babl_space_from_icc (const char   *icc_data,
      if (phosporant != 0)
      {
        *error = "unhandled phosporants, please report bug against babl with profile";
+       babl_mutex_unlock (babl_space_mutex);
        return NULL;
      }
      if (channels != 3)
      {
        *error = "unexpected non 3 count of channels";
+       babl_mutex_unlock (babl_space_mutex);
        return NULL;
      }
 
@@ -1250,6 +1269,7 @@ babl_space_from_icc (const char   *icc_data,
        ret->space.icc_profile = malloc (icc_length);
        memcpy (ret->space.icc_profile, icc_data, icc_length);
 
+       babl_mutex_unlock (babl_space_mutex);
        return ret;
      }
   }
@@ -1257,6 +1277,7 @@ babl_space_from_icc (const char   *icc_data,
   }
 
   babl_free (state);
+  babl_mutex_unlock (babl_space_mutex);
   return NULL;
 }
 
index f7939a1b32702d62ba29cdfae4f3508e3ee14ace..94043d3c4f62e8388b01addb43526a8e0071168b 100644 (file)
@@ -84,6 +84,7 @@ BablMutex *babl_format_mutex;
 BablMutex *babl_debug_mutex;
 #endif
 BablMutex *babl_reference_mutex;
+BablMutex *babl_space_mutex;
 
 void
 babl_internal_init (void)
@@ -93,6 +94,7 @@ babl_internal_init (void)
   babl_fish_mutex = babl_mutex_new ();
   babl_format_mutex = babl_mutex_new ();
   babl_reference_mutex = babl_mutex_new ();
+  babl_space_mutex = babl_mutex_new ();
 #if BABL_DEBUG_MEM
   babl_debug_mutex = babl_mutex_new ();
 #endif
index 56e95e4a23d0184a5cdca60c92ecdff70e1faf4e..8b8ebd64deac6795b01c6d61ba10f2adf9b42d44 100644 (file)
@@ -249,6 +249,7 @@ extern int   babl_in_fish_path;
 extern BablMutex *babl_format_mutex;
 extern BablMutex *babl_fish_mutex;
 extern BablMutex *babl_reference_mutex;
+extern BablMutex *babl_space_mutex;
 
 #define BABL_DEBUG_MEM 0
 #if BABL_DEBUG_MEM