heif_decode_image() returns heif_status=heif_error_Ok although returned heif_image is null while under resource limits
Google's oss-fuzz opened issue 462673424 about a claimed crash under this recently updated GraphicsMagick code:
heif_status=heif_decode_image(heif_image_handle,
&heif_image,
heif_colorspace_decode, /* Chose preferred colorspace */
heif_chroma_decode,
decode_options);
}
heif_decoding_options_free(decode_options);
if (heif_status.code == heif_error_Memory_allocation_error)
ThrowHEIFThrowReadImageFrameException(ResourceLimitError,MemoryAllocationFailed,image);
if (heif_status.code != heif_error_Ok)
{
if (image->logging)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"heif_decode_image() reports error \"%s\"",
heif_status.message);
ThrowHEIFThrowReadImageFrameException(CorruptImageError, AnErrorHasOccurredReadingFromFile, image);
}
/*
Trace decoding warnings
*/
if (image->logging)
{
int i;
for (i = 0;; i++)
{
int n;
n = heif_image_get_decoding_warnings(heif_image,i,&heif_status, 1);
if (n == 0)
break;
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"Warning: %s", heif_status.message);
}
}
Indeed, I am able to reproduce this in gdb:
gdb ~/build/GM-16-static-debug-noopenmp/utilities/gm
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /home/bfriesen/build/GM-16-static-debug-noopenmp/utilities/gm...
(gdb) r convert -debug coder,resource clusterfuzz-testcase-coder_HEIF_fuzzer-4787858637651968.avif info:-
Starting program: /home/bfriesen/build/GM-16-static-debug-noopenmp/utilities/gm convert -debug coder,resource clusterfuzz-testcase-coder_HEIF_fuzzer-4787858637651968.avif info:-
Downloading separate debug info for system-supplied DSO at 0x7ffff7fc3000
Downloading separate debug info for /lib/x86_64-linux-gnu/libwebpmux.so.3
Downloading separate debug info for /lib/x86_64-linux-gnu/libwebp.so.7
Downloading separate debug info for /lib/x86_64-linux-gnu/libfreetype.so.6
Downloading separate debug info for /lib/x86_64-linux-gnu/libpng16.so.16
Downloading separate debug info for /lib/x86_64-linux-gnu/libxml2.so.2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Downloading separate debug info for /usr/local/lib/libopenh264.so.8
Downloading separate debug info for /lib/x86_64-linux-gnu/libsharpyuv.so.0
Downloading separate debug info for /lib/x86_64-linux-gnu/liblzma.so.5
Downloading separate debug info for /lib/x86_64-linux-gnu/libXi.so.6
Downloading separate debug info for /lib/x86_64-linux-gnu/libcrypto.so.3
Downloading separate debug info for /lib/x86_64-linux-gnu/libxcb.so.1
Downloading separate debug info for /lib/x86_64-linux-gnu/libbsd.so.0
Downloading separate debug info for /lib/x86_64-linux-gnu/libmd.so.0
09:35:50 0:0.000377 0.000u 23677 resource.c/_UpdateMagickResourceHighwater/1118/Resource:
Ignored request to set read highwater to 451B
09:35:50 0:0.000418 0.000u 23677 magic.c/GetMagickFileFormat/310/Coder:
Magick: AVIF ("AV1 image")
09:35:50 0:0.000457 0.000u 23677 constitute.c/ReadImage/1676/Coder:
Invoking "AVIF" decoder (HEIF Image Format) subimage=0 subrange=0
09:35:50 0:0.014207 0.000u 23677 resource.c/AcquireMagickResource/248/Resource:
memory +451B/451B/256.0MiB
09:35:50 0:0.014229 0.000u 23677 heif.c/ReadHEIFImage/1566/Coder:
Reading file into in-memory blob...
09:35:50 0:0.014240 0.000u 23677 heif.c/ReadHEIFImage/1571/Coder:
Done!
09:35:50 0:0.014272 0.000u 23677 heif.c/apply_security_limits/572/Coder:
security limits: max-memory-block-size = 268435456
09:35:50 0:0.014277 0.000u 23677 heif.c/apply_security_limits/576/Coder:
security limits: max-total-memory = 268435456
09:35:50 0:0.014284 0.000u 23677 heif.c/apply_security_limits/593/Coder:
security limits: max_image_size_pixels = 4194304
09:35:50 0:0.014291 0.000u 23677 heif.c/ReadHEIFImage/1592/Coder:
HEIF Brand: avif
09:35:50 0:0.014316 0.000u 23677 heif.c/ReadHEIFImage/1620/Coder:
Compatible HEIF Brands: avif, m
09:35:50 0:0.014324 0.000u 23677 heif.c/ReadHEIFImage/1629/Coder:
MIME Type: image/avif
09:35:50 0:0.014329 0.000u 23677 heif.c/ReadHEIFImage/1647/Coder:
ignore-transformations: False
09:35:50 0:0.014403 0.000u 23677 heif.c/ReadHEIFImage/1669/Coder:
Number of top level images: 1 (reading primary image only)
09:35:50 0:0.014412 0.000u 23677 heif.c/ReadHEIFImageFrame/901/Coder:
Geometry: 1x1
09:35:50 0:0.014418 0.000u 23677 heif.c/ReadHEIFImageFrame/907/Coder:
Matte: False
09:35:50 0:0.014423 0.000u 23677 heif.c/ReadHEIFImageFrame/921/Coder:
Preferred colorspace: RGB, Preferred chroma: 444
09:35:50 0:0.014429 0.000u 23677 heif.c/ReadColorProfile/432/Coder:
Found color profile of type "nclx"
09:35:50 0:0.014435 0.000u 23677 heif.c/ReadHEIFImageFrame/1004/Coder:
Decoding image...
Program received signal SIGSEGV, Segmentation fault.
heif_image_get_decoding_warnings (image=0x0, first_warning_idx=0, out_warnings=0x7fffffffafa0, max_output_buffer_entries=1)
at /home/bfriesen/src/libheif/libheif/api/libheif/heif_image.cc:287
287 return (int) image->image->get_warnings().size();
(gdb) bt
#0 heif_image_get_decoding_warnings (image=0x0, first_warning_idx=0, out_warnings=0x7fffffffafa0, max_output_buffer_entries=1)
at /home/bfriesen/src/libheif/libheif/api/libheif/heif_image.cc:287
#1 0x00005555556f9542 in ReadHEIFImageFrame (heif_image_handle=0x55555599e560, ignore_transformations=0, image=0x555555991e70, image_info=0x55555598fb60, exception=0x7fffffffd3e0)
at /home/bfriesen/src/GM/coders/heif.c:1071
#2 0x00005555556fbb7d in ReadHEIFImage (image_info=0x55555598fb60, exception=0x7fffffffd3e0) at /home/bfriesen/src/GM/coders/heif.c:1688
#3 0x00005555555b2480 in ReadImage (image_info=0x55555598b9d0, exception=0x7fffffffd3e0) at /home/bfriesen/src/GM/magick/constitute.c:1682
#4 0x0000555555577a38 in ConvertImageCommand (image_info=0x55555598b9d0, argc=5, argv=0x55555598db30, metadata=0x0, exception=0x7fffffffd3e0)
at /home/bfriesen/src/GM/magick/command.c:4541
#5 0x000055555558772c in MagickCommand (image_info=0x55555598b9d0, argc=5, argv=0x7fffffffddb0, metadata=0x7fffffffd3c8, exception=0x7fffffffd3e0)
at /home/bfriesen/src/GM/magick/command.c:9067
#6 0x00005555555a366f in GMCommandSingle (argc=5, argv=0x7fffffffddb0) at /home/bfriesen/src/GM/magick/command.c:17767
#7 0x00005555555a37a1 in GMCommand (argc=6, argv=0x7fffffffdda8) at /home/bfriesen/src/GM/magick/command.c:17820
#8 0x000055555556a81d in main (argc=6, argv=0x7fffffffdda8) at /home/bfriesen/src/GM/utilities/gm.c:61
(gdb) p heif_status
$2 = {code = heif_error_Ok, subcode = heif_suberror_Unspecified, message = 0x7ffff7dcbc8b "Success"}
(gdb) p heif_image
$3 = (struct heif_image *) 0x0
(gdb)
From the above, I see that heif_decode_image() returned heif_error_Ok even though it did not return an image. This seems like a significant problem!
The security limits applied are reported in the program tracing.
I should mention that the libheif build I was using was a couple of weeks old. When I tried to replicate the issue using the older libheif, libheif was failing elsewhere and crashing
while under the reduced memory limits.
I tried this on your image with the current master branch and also with v1.20.1, but I cannot reproduce it since the image decoded fine with both versions:
I see that you have a lower security limit for the image size:
max_image_size_pixels = 4194304
This is still larger than the image, but if I further reduce it to be smaller than the image,heif_decode_image() returns an error and also a NULL image.
I have since enhanced the tracing of libheif security_limits to include the values set by libheif, as well as values over-ridden by GraphicsMagick. This is the full trace of the libheif security_limits:
security limits: max_memory_block_size = 268435456 security limits: max_total_memory = 268435456 security limits: max_image_size_pixels = 4194304 security limits: max_image_size_pixels = 4194304 security limits: max_number_of_tiles = 16777216 security limits: max_bayer_pattern_pixels = 256 security limits: max_items = 1000 security limits: max_color_profile_size = 104857600 security limits: max_memory_block_size = 268435456 security limits: max_components = 256 security limits: max_iloc_extents_per_item = 32 security limits: max_size_entity_group = 64 security limits: max_children_per_box = 100 security limits: max_total_memory = 268435456 security limits: max_sample_description_box_entries = 1024 security limits: max_sample_group_description_box_entries = 1024
and this is the full output from tracing from GraphicsMagick given '-debug coder':
08:28:10 0:0.000193 0.000u 33209 magic.c/GetMagickFileFormat/310/Coder: Magick: HEIF ("HEIF") 08:28:10 0:0.000227 0.000u 33209 constitute.c/ReadImage/1676/Coder: Invoking "HEIF" decoder (HEIF Image Format) subimage=0 subrange=0 08:28:10 0:0.000585 0.000u 33209 heif.c/ReadHEIFImage/1631/Coder: Reading file into in-memory blob... 08:28:10 0:0.000597 0.000u 33209 heif.c/ReadHEIFImage/1636/Coder: Done! 08:28:10 0:0.000639 0.000u 33209 heif.c/apply_security_limits/572/Coder: security limits: max_memory_block_size = 268435456 08:28:10 0:0.000643 0.000u 33209 heif.c/apply_security_limits/576/Coder: security limits: max_total_memory = 268435456 08:28:10 0:0.000649 0.000u 33209 heif.c/apply_security_limits/593/Coder: security limits: max_image_size_pixels = 4194304 08:28:10 0:0.000653 0.000u 33209 heif.c/apply_security_limits/626/Coder: security limits: max_image_size_pixels = 4194304 08:28:10 0:0.000658 0.000u 33209 heif.c/apply_security_limits/633/Coder: security limits: max_number_of_tiles = 16777216 08:28:10 0:0.000662 0.000u 33209 heif.c/apply_security_limits/640/Coder: security limits: max_bayer_pattern_pixels = 256 08:28:10 0:0.000667 0.010u 33209 heif.c/apply_security_limits/647/Coder: security limits: max_items = 1000 08:28:10 0:0.000672 0.010u 33209 heif.c/apply_security_limits/654/Coder: security limits: max_color_profile_size = 104857600 08:28:10 0:0.000676 0.010u 33209 heif.c/apply_security_limits/661/Coder: security limits: max_memory_block_size = 268435456 08:28:10 0:0.000681 0.010u 33209 heif.c/apply_security_limits/668/Coder: security limits: max_components = 256 08:28:10 0:0.000685 0.010u 33209 heif.c/apply_security_limits/675/Coder: security limits: max_iloc_extents_per_item = 32 08:28:10 0:0.000690 0.010u 33209 heif.c/apply_security_limits/682/Coder: security limits: max_size_entity_group = 64 08:28:10 0:0.000694 0.010u 33209 heif.c/apply_security_limits/689/Coder: security limits: max_children_per_box = 100 08:28:10 0:0.000698 0.010u 33209 heif.c/apply_security_limits/699/Coder: security limits: max_total_memory = 268435456 08:28:10 0:0.000702 0.010u 33209 heif.c/apply_security_limits/707/Coder: security limits: max_sample_description_box_entries = 1024 08:28:10 0:0.000707 0.010u 33209 heif.c/apply_security_limits/715/Coder: security limits: max_sample_group_description_box_entries = 1024 08:28:10 0:0.000713 0.010u 33209 heif.c/ReadHEIFImage/1664/Coder: HEIF Brand: " " 08:28:10 0:0.000737 0.010u 33209 heif.c/ReadHEIFImage/1696/Coder: Compatible HEIF brands: , mif1, ,
08:28:10 0:0.000747 0.010u 33209 heif.c/ReadHEIFImage/1710/Coder: MIME Type: 08:28:10 0:0.000752 0.010u 33209 heif.c/ReadHEIFImage/1728/Coder: ignore-transformations: False 08:28:10 0:0.000839 0.010u 33209 heif.c/ReadHEIFImage/1750/Coder: Number of top level images: 1 (reading primary image only) 08:28:10 0:0.000849 0.010u 33209 heif.c/ReadHEIFImageFrame/959/Coder: Geometry: 0x0 08:28:10 0:0.000854 0.010u 33209 heif.c/ReadHEIFImageFrame/965/Coder: Matte: False 08:28:10 0:0.000860 0.010u 33209 heif.c/ReadHEIFImageFrame/979/Coder: Preferred colorspace: RGB, Preferred chroma: 444 08:28:10 0:0.000865 0.010u 33209 heif.c/ReadColorProfile/432/Coder: Found color profile of type "nclx" 08:28:10 0:0.000870 0.010u 33209 heif.c/ReadHEIFImageFrame/1062/Coder: Decoding image... 08:28:10 0:0.067263 0.070u 33209 heif.c/ReadHEIFImageFrame/1121/Coder: heif_decode_image() reports heif_error_Ok but failed to return an image! 08:28:10 0:0.067309 0.070u 33209 constitute.c/ReadImage/1702/Coder: Returned from "HEIF" decoder, returned image is NULL!
It may be that libheif sets some of the default limits based on properties of the host it is running on.
The problem is still occurring, even though I did something to cause the oss-fuzz issue to be closed.
Can you tell me which libheif version or commit you are using so that I can use the same?
% git show commit 388d4b35697cb06e18a36d24fea9da83fdc42fee (HEAD -> master, origin/master, origin/HEAD) Author: Dirk Farin [email protected] Date: Sat Nov 29 22:51:36 2025 +0100
fix invalid read during color-conversion when alpha image bpp differs from main image (#1626)
Oss-fuzz reports that this issue has been fixed.