Commit a878f3f1f for imagemagick.org
commit a878f3f1f062a925d0b1926d49e3440f7e4a3362
Author: Cristy <urban-warrior@imagemagick.org>
Date: Thu Nov 5 10:56:13 2026 -0500
https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-v56x-r6p7-8v88
diff --git a/MagickCore/cache.c b/MagickCore/cache.c
index 4c0486206..bdff96554 100644
--- a/MagickCore/cache.c
+++ b/MagickCore/cache.c
@@ -144,6 +144,9 @@ static Quantum
const size_t,ExceptionInfo *),
*QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
const size_t,ExceptionInfo *),
+ *QueueAuthenticPixelCacheNexusInternal(Image *,const ssize_t,const ssize_t,
+ const size_t,const size_t,const MagickBooleanType,NexusInfo **,
+ ExceptionInfo *),
*SetPixelCacheNexusPixels(const CacheInfo *magick_restrict,const MapMode,
const ssize_t,const ssize_t,const size_t,const size_t,
const MagickBooleanType,NexusInfo *magick_restrict,ExceptionInfo *)
@@ -1410,12 +1413,13 @@ MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
*/
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
- pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
- nexus_info,exception);
- if (pixels == (Quantum *) NULL)
+ pixels=QueueAuthenticPixelCacheNexusInternal(image,x,y,columns,rows,
+ MagickTrue,&nexus_info,exception);
+ if ((pixels == (Quantum *) NULL) || (nexus_info == (NexusInfo *) NULL))
return((Quantum *) NULL);
cache_info=(CacheInfo *) image->cache;
assert(cache_info->signature == MagickCoreSignature);
+ assert(nexus_info->signature == MagickCoreSignature);
if (nexus_info->authentic_pixel_cache != MagickFalse)
return(pixels);
if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
@@ -4347,12 +4351,40 @@ MagickExport MagickBooleanType PersistPixelCache(Image *image,
% o exception: return any errors or warnings in this structure.
%
*/
-MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
+
+static inline ssize_t GetPixelCacheNexusIndex(
+ const CacheInfo *magick_restrict cache_info,
+ const NexusInfo *magick_restrict nexus_info)
+{
+ const NexusInfo
+ *magick_restrict base;
+
+ size_t
+ number_nexus;
+
+ /*
+ Return the index of nexus_info within the nexus array owned by cache_info.
+ */
+ if ((cache_info == (const CacheInfo *) NULL) ||
+ (cache_info->nexus_info == (NexusInfo **) NULL) ||
+ (nexus_info == (const NexusInfo *) NULL))
+ return(-1);
+ base=(*cache_info->nexus_info);
+ number_nexus=2*cache_info->number_threads;
+ if ((nexus_info < base) || (nexus_info >= (base+number_nexus)))
+ return(-1);
+ if (cache_info->nexus_info[nexus_info-base] != nexus_info)
+ return(-1);
+ return((ssize_t) (nexus_info-base));
+}
+
+static Quantum *QueueAuthenticPixelCacheNexusInternal(Image *image,
const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
- const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
+ const MagickBooleanType clone,NexusInfo **nexus_info,ExceptionInfo *exception)
{
CacheInfo
- *magick_restrict cache_info;
+ *magick_restrict cache_info,
+ *magick_restrict source_info;
MagickOffsetType
offset;
@@ -4363,16 +4395,58 @@ MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
Quantum
*magick_restrict pixels;
+ size_t
+ source_threads;
+
+ ssize_t
+ nexus_index;
+
/*
Validate pixel cache geometry.
*/
assert(image != (const Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(image->cache != (Cache) NULL);
+ assert(nexus_info != (NexusInfo **) NULL);
+ source_info=(CacheInfo *) image->cache;
+ source_threads=source_info->number_threads;
+ nexus_index=GetPixelCacheNexusIndex(source_info,*nexus_info);
cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
if (cache_info == (Cache) NULL)
- return((Quantum *) NULL);
+ {
+ if ((nexus_index >= 0) && ((CacheInfo *) image->cache != source_info))
+ *nexus_info=(NexusInfo *) NULL; /* never hand back a stale nexus */
+ return((Quantum *) NULL);
+ }
assert(cache_info->signature == MagickCoreSignature);
+ if ((nexus_index >= 0) && (cache_info != source_info))
+ {
+ NexusInfo
+ *magick_restrict live_nexus;
+
+ /*
+ The cache was replaced: resolve the nexus from the live cache.
+ */
+ live_nexus=(NexusInfo *) NULL;
+ if ((cache_info->nexus_info != (NexusInfo **) NULL) &&
+ (source_threads <= cache_info->number_threads))
+ {
+ if (nexus_index < (ssize_t) source_threads)
+ live_nexus=cache_info->nexus_info[nexus_index];
+ else
+ live_nexus=cache_info->nexus_info[nexus_index-(ssize_t)
+ source_threads]->virtual_nexus;
+ }
+ *nexus_info=live_nexus;
+ if (live_nexus == (NexusInfo *) NULL)
+ {
+ (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+ "UnableToGetCacheNexus","`%s'",image->filename);
+ return((Quantum *) NULL);
+ }
+ }
+ if (*nexus_info == (NexusInfo *) NULL)
+ return((Quantum *) NULL);
if ((columns == 0) || (rows == 0) ||
(cache_info->columns == 0) || (cache_info->rows == 0) ||
(x < 0) || (y < 0) ||
@@ -4404,9 +4478,17 @@ MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
((image->channels & WriteMaskChannel) != 0) ||
((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
- nexus_info,exception);
+ *nexus_info,exception);
return(pixels);
}
+
+MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
+ const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
+ const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+ return(QueueAuthenticPixelCacheNexusInternal(image,x,y,columns,rows,clone,
+ &nexus_info,exception));
+}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%