diff --git a/src/failing-alloc.c b/src/failing-alloc.c new file mode 100644 index 000000000..1bf18cd67 --- /dev/null +++ b/src/failing-alloc.c @@ -0,0 +1,57 @@ +/* + * Copyright © 2020 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include +#include + +int alloc_state = 0; + +__attribute__((no_sanitize("integer"))) +static int fastrand () +{ + if (!alloc_state) return 1; + /* Based on https://software.intel.com/content/www/us/en/develop/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor.html */ + alloc_state = (214013 * alloc_state + 2531011); + return (alloc_state >> 16) & 0x7FFF; +} + +void* hb_malloc_impl (size_t size) +{ + return (fastrand () % 16) ? malloc (size) : NULL; +} + +void* hb_calloc_impl (size_t nmemb, size_t size) +{ + return (fastrand () % 16) ? calloc (nmemb, size) : NULL; +} + +void* hb_realloc_impl (void *ptr, size_t size) +{ + return (fastrand () % 16) ? realloc (ptr, size) : NULL; +} + +void hb_free_impl (void *ptr) +{ + return free (ptr); +} diff --git a/src/meson.build b/src/meson.build index 6da8e839b..bac43a556 100644 --- a/src/meson.build +++ b/src/meson.build @@ -397,6 +397,14 @@ else hb_so_version = '0' endif +if get_option('fuzzer_ldflags') != '' + extra_hb_cpp_args += ['-DHB_CUSTOM_MALLOC'] + hb_sources += 'failing-alloc.c' + hb_subset_sources += 'failing-alloc.c' + hb_icu_sources += 'failing-alloc.c' + hb_gobject_sources += 'failing-alloc.c' +endif + libharfbuzz = library('harfbuzz', hb_sources, include_directories: incconfig, dependencies: harfbuzz_deps, diff --git a/test/fuzzing/hb-draw-fuzzer.cc b/test/fuzzing/hb-draw-fuzzer.cc index 1baefdaef..977c9aa20 100644 --- a/test/fuzzing/hb-draw-fuzzer.cc +++ b/test/fuzzing/hb-draw-fuzzer.cc @@ -115,6 +115,8 @@ static void misc_calls_for_gid (hb_face_t *face, hb_font_t *font, hb_set_t *set, extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + alloc_state = size; /* see src/failing-alloc.c */ + hb_blob_t *blob = hb_blob_create ((const char *) data, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr); hb_face_t *face = hb_face_create (blob, 0); diff --git a/test/fuzzing/hb-fuzzer.hh b/test/fuzzing/hb-fuzzer.hh index d0c617e09..ca42c6839 100644 --- a/test/fuzzing/hb-fuzzer.hh +++ b/test/fuzzing/hb-fuzzer.hh @@ -2,3 +2,11 @@ #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +#ifdef HB_IS_IN_FUZZER +/* See src/failing-alloc.c */ +extern "C" int alloc_state; +#else +/* Just a dummy global variable */ +static int alloc_state = 0; +#endif diff --git a/test/fuzzing/hb-set-fuzzer.cc b/test/fuzzing/hb-set-fuzzer.cc index acfe074d6..79b9fc52f 100644 --- a/test/fuzzing/hb-set-fuzzer.cc +++ b/test/fuzzing/hb-set-fuzzer.cc @@ -32,6 +32,8 @@ static hb_set_t *create_set (const uint32_t *value_array, int count) extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) { + alloc_state = size; /* see src/failing-alloc.c */ + if (size < sizeof (instructions_t)) return 0; diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc index d1687b2ca..e551786bc 100644 --- a/test/fuzzing/hb-shape-fuzzer.cc +++ b/test/fuzzing/hb-shape-fuzzer.cc @@ -33,7 +33,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) hb_buffer_t *buffer = hb_buffer_create (); hb_buffer_add_utf8 (buffer, text, -1, 0, -1); hb_buffer_guess_segment_properties (buffer); + alloc_state = size; /* see src/failing-alloc.c TODO: move to top */ hb_shape (font, buffer, nullptr, 0); + alloc_state = 0; /* no failing alloc, TODO: remove */ hb_buffer_destroy (buffer); } @@ -45,12 +47,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) memcpy (text32, data + size - len, len); /* Misc calls on font. */ + alloc_state = size; /* see src/failing-alloc.c TODO: move to top */ text32[10] = test_font (font, text32[15]) % 256; + alloc_state = 0; /* no failing alloc, TODO: remove */ hb_buffer_t *buffer = hb_buffer_create (); hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1); hb_buffer_guess_segment_properties (buffer); + alloc_state = size; /* see src/failing-alloc.c TODO: move to top */ hb_shape (font, buffer, nullptr, 0); + alloc_state = 0; /* no failing alloc, TODO: remove */ hb_buffer_destroy (buffer); hb_font_destroy (font); diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc index 6960816ec..115a63562 100644 --- a/test/fuzzing/hb-subset-fuzzer.cc +++ b/test/fuzzing/hb-subset-fuzzer.cc @@ -67,6 +67,8 @@ trySubset (hb_face_t *face, extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + alloc_state = size; /* see src/failing-alloc.c */ + hb_blob_t *blob = hb_blob_create ((const char *)data, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr); hb_face_t *face = hb_face_create (blob, 0); diff --git a/test/fuzzing/meson.build b/test/fuzzing/meson.build index b67f87334..9037a9af0 100644 --- a/test/fuzzing/meson.build +++ b/test/fuzzing/meson.build @@ -10,15 +10,17 @@ foreach file_name : tests sources = [file_name] fuzzer_ldflags = [] + extra_cpp_args = [] if get_option('fuzzer_ldflags') == '' sources += 'main.cc' else fuzzer_ldflags += get_option('fuzzer_ldflags').split() + extra_cpp_args += '-DHB_IS_IN_FUZZER' endif exe = executable(test_name, sources, - cpp_args: cpp_args, + cpp_args: cpp_args + extra_cpp_args, include_directories: [incconfig, incsrc], link_args: fuzzer_ldflags, link_with: [libharfbuzz, libharfbuzz_subset],