summaryrefslogtreecommitdiff
path: root/Build/source/libs/freetype2/freetype-src/src/tools/ftfuzzer/ftfuzzer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/freetype2/freetype-src/src/tools/ftfuzzer/ftfuzzer.cc')
-rw-r--r--Build/source/libs/freetype2/freetype-src/src/tools/ftfuzzer/ftfuzzer.cc310
1 files changed, 310 insertions, 0 deletions
diff --git a/Build/source/libs/freetype2/freetype-src/src/tools/ftfuzzer/ftfuzzer.cc b/Build/source/libs/freetype2/freetype-src/src/tools/ftfuzzer/ftfuzzer.cc
new file mode 100644
index 00000000000..b33ed22c871
--- /dev/null
+++ b/Build/source/libs/freetype2/freetype-src/src/tools/ftfuzzer/ftfuzzer.cc
@@ -0,0 +1,310 @@
+// ftfuzzer.cc
+//
+// A fuzzing function to test FreeType with libFuzzer.
+//
+// Copyright 2015 by
+// David Turner, Robert Wilhelm, and Werner Lemberg.
+//
+// This file is part of the FreeType project, and may only be used,
+// modified, and distributed under the terms of the FreeType project
+// license, LICENSE.TXT. By continuing to use, modify, or distribute
+// this file you indicate that you have read the license and
+// understand and accept it fully.
+
+
+// we use `unique_ptr', `decltype', and other gimmicks defined since C++11
+#if __cplusplus < 201103L
+# error "a C++11 compiler is needed"
+#endif
+
+#include <archive.h>
+#include <archive_entry.h>
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+
+ using namespace std;
+
+
+#include <ft2build.h>
+
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_CACHE_H
+#include FT_CACHE_CHARMAP_H
+#include FT_CACHE_IMAGE_H
+#include FT_CACHE_SMALL_BITMAPS_H
+#include FT_SYNTHESIS_H
+#include FT_ADVANCES_H
+#include FT_OUTLINE_H
+#include FT_BBOX_H
+#include FT_MODULE_H
+#include FT_CFF_DRIVER_H
+#include FT_TRUETYPE_DRIVER_H
+#include FT_MULTIPLE_MASTERS_H
+
+
+ static FT_Library library;
+ static int InitResult;
+
+
+ struct FT_Global {
+ FT_Global() {
+ InitResult = FT_Init_FreeType( &library );
+ }
+ ~FT_Global() {
+ FT_Done_FreeType( library );
+ }
+ };
+
+ FT_Global global_ft;
+
+
+ static int
+ archive_read_entry_data( struct archive *ar,
+ vector<FT_Byte> *vw )
+ {
+ int r;
+ const FT_Byte* buff;
+ size_t size;
+ int64_t offset;
+
+ for (;;)
+ {
+ r = archive_read_data_block( ar,
+ reinterpret_cast<const void**>( &buff ),
+ &size,
+ &offset );
+ if ( r == ARCHIVE_EOF )
+ return ARCHIVE_OK;
+ if ( r != ARCHIVE_OK )
+ return r;
+
+ vw->insert( vw->end(), buff, buff + size );
+ }
+ }
+
+
+ static vector<vector<FT_Byte>>
+ parse_data( const uint8_t* data,
+ size_t size )
+ {
+ struct archive_entry* entry;
+ int r;
+ vector<vector<FT_Byte>> files;
+
+ unique_ptr<struct archive,
+ decltype ( archive_read_free )*> a( archive_read_new(),
+ archive_read_free );
+
+ // activate reading of uncompressed tar archives
+ archive_read_support_format_tar( a.get() );
+
+ // the need for `const_cast' was removed with libarchive commit be4d4dd
+ if ( !( r = archive_read_open_memory(
+ a.get(),
+ const_cast<void*>(static_cast<const void*>( data ) ),
+ size ) ) )
+ {
+ unique_ptr<struct archive,
+ decltype ( archive_read_close )*> a_open( a.get(),
+ archive_read_close );
+
+ // read files contained in archive
+ for (;;)
+ {
+ r = archive_read_next_header( a_open.get(), &entry );
+ if ( r == ARCHIVE_EOF )
+ break;
+ if ( r != ARCHIVE_OK )
+ break;
+
+ vector<FT_Byte> entry_data;
+ r = archive_read_entry_data( a.get(), &entry_data );
+ if ( r != ARCHIVE_OK )
+ break;
+
+ files.push_back( move( entry_data ) );
+ }
+ }
+
+ if ( files.size() == 0 )
+ files.emplace_back( data, data + size );
+
+ return files;
+ }
+
+
+ static void
+ setIntermediateAxis( FT_Face face )
+ {
+ // only handle Multiple Masters and GX variation fonts
+ if ( !( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) )
+ return;
+
+ // get variation data for current instance
+ FT_MM_Var* variations_ptr = nullptr;
+ if ( FT_Get_MM_Var( face, &variations_ptr ) )
+ return;
+
+ unique_ptr<FT_MM_Var,
+ decltype ( free )*> variations( variations_ptr, free );
+ vector<FT_Fixed> coords( variations->num_axis );
+
+ // select an arbitrary instance
+ for ( unsigned int i = 0; i < variations->num_axis; i++ )
+ coords[i] = ( variations->axis[i].minimum +
+ variations->axis[i].def ) / 2;
+
+ if ( FT_Set_Var_Design_Coordinates( face,
+ coords.size(),
+ coords.data() ) )
+ return;
+ }
+
+
+ // the interface function to the libFuzzer library
+ extern "C" int
+ LLVMFuzzerTestOneInput( const uint8_t* data,
+ size_t size_ )
+ {
+ assert( !InitResult );
+
+ if ( size_ < 1 )
+ return 0;
+
+ const vector<vector<FT_Byte>>& files = parse_data( data, size_ );
+
+ FT_Face face;
+ FT_Int32 load_flags = FT_LOAD_DEFAULT;
+#if 0
+ FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL;
+#endif
+
+ // We use a conservative approach here, at the cost of calling
+ // `FT_New_Face' quite often. The idea is that the fuzzer should be
+ // able to try all faces and named instances of a font, expecting that
+ // some faces don't work for various reasons, e.g., a broken subfont, or
+ // an unsupported NFNT bitmap font in a Mac dfont resource that holds
+ // more than a single font.
+
+ // get number of faces
+ if ( FT_New_Memory_Face( library,
+ files[0].data(),
+ (FT_Long)files[0].size(),
+ -1,
+ &face ) )
+ return 0;
+ long num_faces = face->num_faces;
+ FT_Done_Face( face );
+
+ // loop over all faces
+ for ( long face_index = 0;
+ face_index < num_faces;
+ face_index++ )
+ {
+ // get number of instances
+ if ( FT_New_Memory_Face( library,
+ files[0].data(),
+ (FT_Long)files[0].size(),
+ -( face_index + 1 ),
+ &face ) )
+ continue;
+ long num_instances = face->style_flags >> 16;
+ FT_Done_Face( face );
+
+ // load face with and without instances
+ for ( long instance_index = 0;
+ instance_index < num_instances + 1;
+ instance_index++ )
+ {
+ if ( FT_New_Memory_Face( library,
+ files[0].data(),
+ (FT_Long)files[0].size(),
+ ( instance_index << 16 ) + face_index,
+ &face ) )
+ continue;
+
+ // if we have more than a single input file coming from an archive,
+ // attach them (starting with the second file) using the order given
+ // in the archive
+ for ( size_t files_index = 1;
+ files_index < files.size();
+ files_index++ )
+ {
+ FT_Open_Args open_args = {};
+ open_args.flags = FT_OPEN_MEMORY;
+ open_args.memory_base = files[files_index].data();
+ open_args.memory_size = (FT_Long)files[files_index].size();
+
+ // the last archive element will be eventually used as the
+ // attachment
+ FT_Attach_Stream( face, &open_args );
+ }
+
+ // loop over all bitmap stroke sizes
+ // and an arbitrary size for outlines
+ for ( long fixed_sizes_index = 0;
+ fixed_sizes_index < face->num_fixed_sizes + 1;
+ fixed_sizes_index++ )
+ {
+ FT_Int32 flags = load_flags;
+
+ if ( !fixed_sizes_index )
+ {
+ // set up 20pt at 72dpi as an arbitrary size
+ FT_Set_Char_Size( face, 20, 20, 72, 72 );
+ flags |= FT_LOAD_NO_BITMAP;
+ }
+ else
+ {
+ FT_Select_Size( face, fixed_sizes_index - 1 );
+ flags |= FT_LOAD_COLOR;
+ }
+
+ // test MM interface only for a face without a selected instance
+ if ( instance_index == 0 )
+ setIntermediateAxis( face );
+
+ // loop over all glyphs
+ for ( unsigned int glyph_index = 0;
+ glyph_index < (unsigned int)face->num_glyphs;
+ glyph_index++ )
+ {
+ if ( FT_Load_Glyph( face, glyph_index, flags ) )
+ continue;
+
+ // Rendering is the most expensive and the least interesting part.
+ //
+ // if ( FT_Render_Glyph( face->glyph, render_mode) )
+ // continue;
+ // FT_GlyphSlot_Embolden( face->glyph );
+
+#if 0
+ FT_Glyph glyph;
+ if ( !FT_Get_Glyph( face->glyph, &glyph ) )
+ FT_Done_Glyph( glyph );
+
+ FT_Outline* outline = &face->glyph->outline;
+ FT_Matrix rot30 = { 0xDDB4, -0x8000, 0x8000, 0xDDB4 };
+
+ FT_Outline_Transform( outline, &rot30 );
+
+ FT_BBox bbox;
+ FT_Outline_Get_BBox( outline, &bbox );
+#endif
+ }
+ }
+ FT_Done_Face( face );
+ }
+ }
+
+ return 0;
+ }
+
+
+// END