Commit 282f455de for imagemagick.org
commit 282f455de5c80a7a0d1a713087db9c8fce344141
Author: Cristy <urban-warrior@imagemagick.org>
Date: Sat Aug 29 11:54:46 2026 -0400
https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-3rjr-534c-8v67
diff --git a/MagickCore/blob-private.h b/MagickCore/blob-private.h
index 5e868c4f9..a16221ee4 100644
--- a/MagickCore/blob-private.h
+++ b/MagickCore/blob-private.h
@@ -148,6 +148,9 @@ extern MagickExport void
MSBOrderLong(unsigned char *,const size_t),
MSBOrderShort(unsigned char *,const size_t);
+extern MagickPrivate void
+ SyncImagesBlob(ImageInfo *,const Image *,Image *);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/MagickCore/blob.c b/MagickCore/blob.c
index 21fbf4c23..5b94733ba 100644
--- a/MagickCore/blob.c
+++ b/MagickCore/blob.c
@@ -2109,8 +2109,9 @@ MagickExport void *ImageToBlob(const ImageInfo *image_info,
else
blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
}
- else if ((status == MagickFalse) && (image->blob->extent == 0))
- blob_info->blob=RelinquishMagickMemory(blob_info->blob);
+ else
+ if ((status == MagickFalse) && (image->blob->extent == 0))
+ blob_info->blob=RelinquishMagickMemory(blob_info->blob);
}
}
else
@@ -2504,6 +2505,7 @@ MagickExport void *ImagesToBlob(const ImageInfo *image_info,Image *images,
images->blob->extent=0;
*images->filename='\0';
status=WriteImages(blob_info,images,images->filename,exception);
+ SyncImagesBlob(blob_info,images,images);
*length=images->blob->length;
blob=DetachBlob(images->blob);
if (blob != (void *) NULL)
@@ -5630,6 +5632,73 @@ static int SyncBlob(const Image *image)
% %
% %
% %
++ S y n c I m a g e s B l o b %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% SyncImagesBlob() re-synchronizes the in-memory blob stream that is shared
+% by an image list. An encoder may grow the blob with SetBlobExtent(), which
+% reallocates (and therefore frees) the buffer that AttachBlob() previously
+% handed to the other images of the list and to image_info->blob. This method
+% replaces every stale reference to that buffer with the current one so that a
+% subsequent AttachBlob(), write, or free never touches freed memory.
+%
+% The format of the SyncImagesBlob method is:
+%
+% void SyncImagesBlob(ImageInfo *image,const Image *image,Image *images)
+%
+% A description of each parameter follows:
+%
+% o image_info: the image info whose blob member is updated; may be NULL.
+%
+% o image: the image that was just written (owner of the live blob).
+%
+% o images: the head of the image list that is being synchronized.
+%
+*/
+MagickPrivate void SyncImagesBlob(ImageInfo *image_info,const Image *image,
+ Image *images)
+{
+ Image
+ *p;
+
+ unsigned char
+ *current,
+ *stale;
+
+ assert(image != (const Image *) NULL);
+ assert(image->signature == MagickCoreSignature);
+ if ((image->blob == (BlobInfo *) NULL) || (image->blob->type != BlobStream))
+ return;
+ current=image->blob->data;
+ stale=(unsigned char *) (image_info != (ImageInfo *) NULL ?
+ image_info->blob : (void *) NULL);
+ if (image_info != (ImageInfo *) NULL)
+ {
+ image_info->blob=(void *) current;
+ image_info->length=image->blob->length;
+ }
+ if ((stale == (unsigned char *) NULL) || (stale == current))
+ return; /* nothing was reallocated */
+ for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
+ {
+ if ((p == image) || (p->blob == (BlobInfo *) NULL))
+ continue;
+ if ((p->blob->type != BlobStream) || (p->blob->data != stale))
+ continue;
+ p->blob->data=current;
+ p->blob->extent=image->blob->extent;
+ p->blob->length=image->blob->length;
+ }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+ T e l l B l o b %
% %
% %
diff --git a/MagickCore/constitute.c b/MagickCore/constitute.c
index 60ea47bfd..a2c653002 100644
--- a/MagickCore/constitute.c
+++ b/MagickCore/constitute.c
@@ -1592,6 +1592,8 @@ MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info,
progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL,
p->client_data);
status&=(MagickStatusType) WriteImage(write_info,p,exception);
+ if (write_info->blob != (void *) NULL)
+ SyncImagesBlob(write_info,p,images);
if (number_images != 1)
(void) SetImageProgressMonitor(p,progress_monitor,p->client_data);
if (write_info->adjoin != MagickFalse)