[draw] Add a fuzzer

Specially checks correctness of the API semantics:
* no move happens when a path is already opened with move-to.
* no path will be left open and close-path will happen at the end of opened paths.
* no path opens with a move-to and will be closed with no length.
* paths start and ending points matches.
* no line/quadratic/cubic command will be issued when no path is started.
This commit is contained in:
Ebrahim Byagowi 2020-02-24 10:34:51 +03:30
parent 2f97aa65e5
commit 036d868913
2 changed files with 126 additions and 0 deletions

View File

@ -64,6 +64,15 @@ hb_set_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la
hb_set_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
hb_set_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la
hb_draw_fuzzer_SOURCES = \
hb-fuzzer.hh \
hb-draw-fuzzer.cc \
main.cc \
$(NULL)
hb_draw_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la
hb_draw_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
hb_draw_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la
check:
EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-shape-fuzzer-tests.py

View File

@ -0,0 +1,117 @@
#include <assert.h>
#include <stdlib.h>
#include <hb-ot.h>
#include "hb-fuzzer.hh"
#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__)
#define HB_UNUSED __attribute__((unused))
#else
#define HB_UNUSED
#endif
struct _user_data_t
{
bool is_open;
unsigned path_len;
hb_position_t path_start_x;
hb_position_t path_start_y;
hb_position_t path_last_x;
hb_position_t path_last_y;
};
static void
_move_to (hb_position_t to_x, hb_position_t to_y, void *user_data_)
{
_user_data_t *user_data = (_user_data_t *) user_data_;
assert (!user_data->is_open);
user_data->is_open = true;
user_data->path_start_x = user_data->path_last_x = to_x;
user_data->path_start_y = user_data->path_last_y = to_y;
}
static void
_line_to (hb_position_t to_x, hb_position_t to_y, void *user_data_)
{
_user_data_t *user_data = (_user_data_t *) user_data_;
assert (user_data->is_open);
++user_data->path_len;
user_data->path_last_x = to_x;
user_data->path_last_y = to_y;
}
static void
_quadratic_to (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
hb_position_t to_x, hb_position_t to_y, void *user_data_)
{
_user_data_t *user_data = (_user_data_t *) user_data_;
assert (user_data->is_open);
++user_data->path_len;
user_data->path_last_x = to_x;
user_data->path_last_y = to_y;
}
static void
_cubic_to (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
hb_position_t to_x, hb_position_t to_y, void *user_data_)
{
_user_data_t *user_data = (_user_data_t *) user_data_;
assert (user_data->is_open);
++user_data->path_len;
user_data->path_last_x = to_x;
user_data->path_last_y = to_y;
}
static void
_close_path (void *user_data_)
{
_user_data_t *user_data = (_user_data_t *) user_data_;
assert (user_data->is_open && user_data->path_len != 0);
user_data->path_len = 0;
user_data->is_open = false;
assert (user_data->path_start_x == user_data->path_last_x &&
user_data->path_start_y == user_data->path_last_y);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
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);
hb_font_t *font = hb_font_create (face);
unsigned num_coords = 0;
if (size) num_coords = data[size - 1];
num_coords = hb_ot_var_get_axis_count (face) > num_coords ? num_coords : hb_ot_var_get_axis_count (face);
int *coords = (int *) calloc (num_coords, sizeof (int));
if (size > num_coords + 1)
for (unsigned i = 0; i < num_coords; ++i)
coords[i] = ((int) data[size - num_coords + i - 1] - 128) * 10;
hb_font_set_var_coords_normalized (font, coords, num_coords);
free (coords);
unsigned glyph_count = hb_face_get_glyph_count (face);
glyph_count = glyph_count > 16 ? 16 : glyph_count;
_user_data_t user_data = {false, 0, 0, 0, 0, 0};
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) _move_to);
hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) _line_to);
hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) _quadratic_to);
hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) _cubic_to);
hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) _close_path);
for (unsigned i = 0; i < glyph_count; ++i)
{
hb_font_draw_glyph (font, i, funcs, &user_data);
assert (!user_data.is_open);
}
hb_draw_funcs_destroy (funcs);
hb_font_destroy (font);
hb_face_destroy (face);
hb_blob_destroy (blob);
return 0;
}