Commit 4fe31106f for imagemagick.org
commit 4fe31106f41fa114945ceaf93226fb151ada0d19
Author: Cristy <urban-warrior@imagemagick.org>
Date: Sat Aug 29 14:14:25 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 a16221ee4..7e08e6884 100644
--- a/MagickCore/blob-private.h
+++ b/MagickCore/blob-private.h
@@ -149,7 +149,7 @@ extern MagickExport void
MSBOrderShort(unsigned char *,const size_t);
extern MagickPrivate void
- SyncImagesBlob(ImageInfo *,const Image *,Image *);
+ SyncBlobStream(ImageInfo *,Image *,Image *);
#if defined(__cplusplus) || defined(c_plusplus)
}
diff --git a/MagickCore/blob.c b/MagickCore/blob.c
index 5b94733ba..83641e0b6 100644
--- a/MagickCore/blob.c
+++ b/MagickCore/blob.c
@@ -2100,6 +2100,7 @@ MagickExport void *ImageToBlob(const ImageInfo *image_info,
image->blob->extent=0;
*image->filename='\0';
status=WriteImage(blob_info,image,exception);
+ SyncBlobStream(blob_info,image,image);
*length=image->blob->length;
blob=DetachBlob(image->blob);
if (blob != (void *) NULL)
@@ -2505,7 +2506,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);
+ SyncBlobStream(blob_info,images,images);
*length=images->blob->length;
blob=DetachBlob(images->blob);
if (blob != (void *) NULL)
@@ -5632,66 +5633,63 @@ static int SyncBlob(const Image *image)
% %
% %
% %
-+ S y n c I m a g e s B l o b %
++ S y n c B l o b S t r e a m %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% 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.
+% SyncBlobStream() transfers ownership of an in-memory blob stream from the
+% image that has just been written back to the owner image and to image info.
+% The method copies the current buffer state onto the owner, refreshes
+% image info, and detaches the borrower so exactly one object owns the memory.
%
-% The format of the SyncImagesBlob method is:
+% The format of the SyncBlobStream method is:
%
-% void SyncImagesBlob(ImageInfo *image,const Image *image,Image *images)
+% void SyncBlobStream(ImageInfo *image,const Image *image,Image *owner)
%
% A description of each parameter follows:
%
-% o image_info: the image info whose blob member is updated; may be NULL.
+% o image_info: image info whose blob/length members are refreshed; may be
+% NULL.
%
-% o image: the image that was just written (owner of the live blob).
+% o owner: the image ImagesToBlob()/ImageToBlob() harvests the blob from
+% (the head of the list).
%
-% o images: the head of the image list that is being synchronized.
+% o image: the image that was just written; may be the owner.
%
*/
-MagickPrivate void SyncImagesBlob(ImageInfo *image_info,const Image *image,
- Image *images)
+MagickPrivate void SyncBlobStream(ImageInfo *image_info,Image *image,
+ Image *owner)
{
- Image
- *p;
-
- unsigned char
- *current,
- *stale;
-
- assert(image != (const Image *) NULL);
+ assert(owner != (Image *) NULL);
+ assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
- if ((image->blob == (BlobInfo *) NULL) || (image->blob->type != BlobStream))
+ if (image->blob == (BlobInfo *) NULL)
+ return;
+ if (image->blob->data == (unsigned char *) NULL)
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->blob=(void *) image->blob->data;
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;
- }
+ if ((image == owner) || (owner->blob == (BlobInfo *) NULL))
+ return;
+ if (owner->blob == (BlobInfo *) NULL)
+ return;
+ /*
+ Promote the live buffer onto the owner before detaching the borrower;
+ DetachBlob() clears image->blob->data.
+ */
+ owner->blob->data=image->blob->data;
+ owner->blob->extent=image->blob->extent;
+ owner->blob->length=image->blob->length;
+ owner->blob->offset=image->blob->offset;
+ owner->blob->quantum=image->blob->quantum;
+ owner->blob->type=BlobStream;
+ owner->blob->exempt=MagickTrue;
+ (void) DetachBlob(image->blob);
}
/*
diff --git a/MagickCore/constitute.c b/MagickCore/constitute.c
index a2c653002..e218688db 100644
--- a/MagickCore/constitute.c
+++ b/MagickCore/constitute.c
@@ -1593,7 +1593,7 @@ MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info,
p->client_data);
status&=(MagickStatusType) WriteImage(write_info,p,exception);
if (write_info->blob != (void *) NULL)
- SyncImagesBlob(write_info,p,images);
+ SyncBlobStream(write_info,p,images);
if (number_images != 1)
(void) SetImageProgressMonitor(p,progress_monitor,p->client_data);
if (write_info->adjoin != MagickFalse)