1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
/*
* HEIF codec.
* Copyright (c) 2017 struktur AG, Joachim Bauch <bauch@struktur.de>
*
* This file is part of libheif.
*
* libheif is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libheif is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libheif. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include "libheif/heif.h"
static const enum heif_colorspace kFuzzColorSpace = heif_colorspace_YCbCr;
static const enum heif_chroma kFuzzChroma = heif_chroma_420;
static void TestDecodeImage(struct heif_context* ctx,
const struct heif_image_handle* handle, size_t filesize)
{
struct heif_image* image = nullptr;
struct heif_error err;
bool primary = heif_image_handle_is_primary_image(handle);
(void) primary;
int width = heif_image_handle_get_width(handle);
int height = heif_image_handle_get_height(handle);
(void)width; (void)height;
assert(width >= 0);
assert(height >= 0);
int metadata_count = heif_image_handle_get_number_of_metadata_blocks(handle, nullptr);
assert(metadata_count >= 0);
assert(static_cast<size_t>(metadata_count) < filesize / sizeof(heif_item_id));
heif_item_id* metadata_ids = static_cast<heif_item_id*>(malloc(metadata_count * sizeof(heif_item_id)));
assert(metadata_ids);
int metadata_ids_count = heif_image_handle_get_list_of_metadata_block_IDs(handle, nullptr, metadata_ids,
metadata_count);
assert(metadata_count == metadata_ids_count);
(void)metadata_ids_count;
for (int i = 0; i < metadata_count; i++) {
heif_image_handle_get_metadata_type(handle, metadata_ids[i]);
heif_image_handle_get_metadata_content_type(handle, metadata_ids[i]);
size_t metadata_size = heif_image_handle_get_metadata_size(handle, metadata_ids[i]);
// This assertion is invalid. Metadata can in fact be larger than the file if there are several
// overlapping iloc extents. Does not make much sense, but it is technically valid.
//assert(metadata_size < filesize);
uint8_t* metadata_data = static_cast<uint8_t*>(malloc(metadata_size));
assert(metadata_data);
heif_image_handle_get_metadata(handle, metadata_ids[i], metadata_data);
free(metadata_data);
}
free(metadata_ids);
err = heif_decode_image(handle, &image, kFuzzColorSpace, kFuzzChroma, nullptr);
if (err.code != heif_error_Ok) {
heif_image_release(image);
return;
}
assert(heif_image_get_colorspace(image) == kFuzzColorSpace);
assert(heif_image_get_chroma_format(image) == kFuzzChroma);
// TODO(fancycode): Should we also check the planes?
heif_image_release(image);
}
static int clip_int(size_t size)
{
return size > INT_MAX ? INT_MAX : static_cast<int>(size);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
struct heif_context* ctx;
struct heif_error err;
struct heif_image_handle* primary_handle = nullptr;
int images_count;
heif_item_id* image_IDs = NULL;
bool explicit_init = size == 0 || data[size - 1] & 1;
if (explicit_init) {
heif_init(nullptr);
}
heif_check_filetype(data, clip_int(size));
heif_main_brand(data, clip_int(size));
heif_get_file_mime_type(data, clip_int(size));
ctx = heif_context_alloc();
assert(ctx);
auto* limits = heif_context_get_security_limits(ctx);
limits->max_memory_block_size = 128 * 1024 * 1024; // 128 MB
err = heif_context_read_from_memory(ctx, data, size, nullptr);
if (err.code != heif_error_Ok) {
// Not a valid HEIF file passed (which is most likely while fuzzing).
goto quit;
}
err = heif_context_get_primary_image_handle(ctx, &primary_handle);
if (err.code == heif_error_Ok) {
assert(heif_image_handle_is_primary_image(primary_handle));
TestDecodeImage(ctx, primary_handle, size);
heif_image_handle_release(primary_handle);
primary_handle = nullptr;
}
images_count = heif_context_get_number_of_top_level_images(ctx);
if (!images_count) {
// File doesn't contain any images.
goto quit;
}
image_IDs = (heif_item_id*) malloc(images_count * sizeof(heif_item_id));
assert(image_IDs);
images_count = heif_context_get_list_of_top_level_image_IDs(ctx, image_IDs, images_count);
if (!images_count) {
// Could not get list of image ids.
goto quit;
}
for (int i = 0; i < images_count; ++i) {
struct heif_image_handle* image_handle = nullptr;
err = heif_context_get_image_handle(ctx, image_IDs[i], &image_handle);
if (err.code != heif_error_Ok) {
heif_image_handle_release(image_handle);
// Ignore, we are only interested in crashes here.
continue;
}
TestDecodeImage(ctx, image_handle, size);
int num_thumbnails = heif_image_handle_get_number_of_thumbnails(image_handle);
for (int t = 0; t < num_thumbnails; ++t) {
struct heif_image_handle* thumbnail_handle = nullptr;
heif_image_handle_get_thumbnail(image_handle, t, &thumbnail_handle);
if (thumbnail_handle) {
TestDecodeImage(ctx, thumbnail_handle, size);
heif_image_handle_release(thumbnail_handle);
}
}
heif_image_handle_release(image_handle);
}
quit:
heif_image_handle_release(primary_handle);
heif_context_free(ctx);
free(image_IDs);
if (explicit_init) {
heif_deinit();
}
return 0;
}
|