Commit ad9c2220 for libheif
commit ad9c2220424de12448c7a502dca82d6beedcb10b
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Thu May 28 12:17:44 2026 +0200
heif_context_add_grid_image: fall back to default options when null
add_new_grid_item() dereferenced encoding_options unconditionally
(set_tile_encoding_options copy + image_orientation read), so passing
a null encoding_options to the public API crashed. Match the behaviour
of heif_context_encode_grid() and allocate a default heif_encoding_options
struct when the caller passes nullptr.
The test's tile-by-tile YCbCr 4:2:0 case now passes nullptr to exercise
this path.
diff --git a/libheif/api/libheif/heif_tiling.cc b/libheif/api/libheif/heif_tiling.cc
index cc9f8171..9dbd6e53 100644
--- a/libheif/api/libheif/heif_tiling.cc
+++ b/libheif/api/libheif/heif_tiling.cc
@@ -232,12 +232,23 @@ heif_error heif_context_add_grid_image(heif_context* ctx,
};
}
+ // Fall back to default options when the caller passes nullptr.
+ // add_new_grid_item() copies these into ImageItem_Grid::m_tile_encoding_options,
+ // so the fallback struct only needs to live for the duration of the call.
+ heif_encoding_options* default_options = nullptr;
+ if (!encoding_options) {
+ default_options = heif_encoding_options_alloc();
+ encoding_options = default_options;
+ }
+
auto generateGridItemResult = ImageItem_Grid::add_new_grid_item(ctx->context.get(),
image_width,
image_height,
static_cast<uint16_t>(tile_rows),
static_cast<uint16_t>(tile_columns),
encoding_options);
+ heif_encoding_options_free(default_options);
+
if (!generateGridItemResult) {
return generateGridItemResult.error_struct(ctx->context.get());
}
diff --git a/tests/encode_grid.cc b/tests/encode_grid.cc
index c39ad480..5640a23c 100644
--- a/tests/encode_grid.cc
+++ b/tests/encode_grid.cc
@@ -398,18 +398,14 @@ TEST_CASE("grid encoding tile-by-tile - uncompressed YCbCr 4:2:0 (extract_area e
heif_context* ctx = heif_context_alloc();
REQUIRE(ctx != nullptr);
- // Build the grid item with an explicit overall image size — this path
- // sidesteps the heif_context_encode_grid limitation of reading tile size
- // via get_width(heif_channel_interleaved) (which would be 0 for planar
- // YCbCr tiles).
- heif_encoding_options* enc_options = heif_encoding_options_alloc();
- REQUIRE(enc_options != nullptr);
-
+ // Build the grid item with an explicit overall image size. Pass nullptr
+ // for encoding_options to also regression-check that heif_context_add_grid_image
+ // falls back to default options rather than dereferencing a null pointer.
heif_image_handle* grid_handle = nullptr;
REQUIRE(heif_context_add_grid_image(ctx,
kCols * kTileSize, kRows * kTileSize,
kCols, kRows,
- enc_options, &grid_handle).code == heif_error_Ok);
+ nullptr, &grid_handle).code == heif_error_Ok);
REQUIRE(grid_handle != nullptr);
for (uint32_t ty = 0; ty < kRows; ++ty) {
@@ -424,7 +420,6 @@ TEST_CASE("grid encoding tile-by-tile - uncompressed YCbCr 4:2:0 (extract_area e
REQUIRE(heif_context_write_to_file(ctx, out_path.c_str()).code == heif_error_Ok);
heif_image_handle_release(grid_handle);
- heif_encoding_options_free(enc_options);
for (heif_image* t : tiles) {
heif_image_release(t);
}