It can now be found at https://github.com/freetype/freetype2-testing/tree/master/fuzzing/src/legacy * src/tools/ftfuzzer: Remove this folder and its contents from the repository.GSoC-2018-nikhil
parent
14032290bf
commit
154832d466
6 changed files with 11 additions and 1010 deletions
@ -1,81 +0,0 @@ |
||||
ftfuzzer |
||||
======== |
||||
|
||||
|
||||
ftfuzzer.cc |
||||
----------- |
||||
|
||||
This file contains a target function for FreeType fuzzing. It can be |
||||
used with libFuzzer (https://llvm.org/docs/LibFuzzer.html) or |
||||
potentially any other similar fuzzer. |
||||
|
||||
Usage: |
||||
|
||||
1. Build `libfreetype.a' and `ftfuzzer.cc' using the most recent |
||||
clang compiler with these flags: |
||||
|
||||
# for fuzzer coverage feedback |
||||
-fsanitize-coverage=edge,8bit-counters |
||||
# for bug checking |
||||
-fsanitize=address,signed-integer-overflow,shift |
||||
|
||||
You also need the header files from the `libarchive' library |
||||
(https://www.libarchive.org/) for handling tar files (see file |
||||
`ftmutator.cc' below for more). |
||||
|
||||
2. Link with `libFuzzer' (it contains `main') and `libarchive'. |
||||
|
||||
3. Run the fuzzer on some test corpus. |
||||
|
||||
The exact flags and commands may vary. |
||||
|
||||
https://github.com/google/oss-fuzz/tree/master/projects/freetype2 |
||||
|
||||
There is a continuous fuzzing bot that runs ftfuzzer. |
||||
|
||||
https://oss-fuzz.com |
||||
|
||||
(You need an account to be able to see coverage reports and the like |
||||
on oss-fuzz.com.) |
||||
|
||||
Check the bot configuration for the most current settings. |
||||
|
||||
|
||||
ftmutator.cc |
||||
------------ |
||||
|
||||
FreeType has the ability to `attach' auxiliary files to a font file, |
||||
providing additional information. The main usage is to load AFM files |
||||
for PostScript Type 1 fonts. |
||||
|
||||
However, libFuzzer currently only supports mutation of a single input |
||||
file. For this reason, `ftmutator.cc' contains a custom fuzzer |
||||
mutator that uses an uncompressed tar file archive as the input. The |
||||
first file in such a tarball gets opened by FreeType as a font, all |
||||
other files are treated as input for `FT_Attach_Stream'. |
||||
|
||||
Compilation is similar to `ftfuzzer.c'. |
||||
|
||||
|
||||
runinput.cc |
||||
----------- |
||||
|
||||
To run the target function on a set of input files, this file contains |
||||
a convenience `main' function. Link it with `ftfuzzer.cc', |
||||
`libfreetype.a', and `libarchive' and run like |
||||
|
||||
./a.out my_tests_inputs/* |
||||
|
||||
---------------------------------------------------------------------- |
||||
|
||||
Copyright 2015-2018 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. |
||||
|
||||
|
||||
--- end of README --- |
@ -1,428 +0,0 @@ |
||||
// ftfuzzer.cc
|
||||
//
|
||||
// A fuzzing function to test FreeType with libFuzzer.
|
||||
//
|
||||
// Copyright 2015-2018 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_DRIVER_H |
||||
#include FT_MULTIPLE_MASTERS_H |
||||
|
||||
|
||||
static FT_Library library; |
||||
static int InitResult; |
||||
|
||||
|
||||
struct FT_Global |
||||
{ |
||||
FT_Global() |
||||
{ |
||||
InitResult = FT_Init_FreeType( &library ); |
||||
if ( InitResult ) |
||||
return; |
||||
|
||||
// try to activate Adobe's CFF engine; it might not be the default
|
||||
unsigned int cff_hinting_engine = FT_HINTING_ADOBE; |
||||
FT_Property_Set( library, |
||||
"cff", |
||||
"hinting-engine", &cff_hinting_engine ); |
||||
} |
||||
|
||||
~FT_Global() |
||||
{ |
||||
FT_Done_FreeType( library ); |
||||
} |
||||
}; |
||||
|
||||
FT_Global global_ft; |
||||
|
||||
|
||||
// We want to select n values at random (without repetition),
|
||||
// with 0 < n <= N. The algorithm is taken from TAoCP, Vol. 2
|
||||
// (Algorithm S, selection sampling technique)
|
||||
struct Random |
||||
{ |
||||
int n; |
||||
int N; |
||||
|
||||
int t; // total number of values so far
|
||||
int m; // number of selected values so far
|
||||
|
||||
uint32_t r; // the current pseudo-random number
|
||||
|
||||
Random( int n_, |
||||
int N_ ) |
||||
: n( n_ ), |
||||
N( N_ ) |
||||
{ |
||||
t = 0; |
||||
m = 0; |
||||
|
||||
// Ideally, this should depend on the input file,
|
||||
// for example, taking the sha256 as input;
|
||||
// however, this is overkill for fuzzying tests.
|
||||
r = 12345; |
||||
} |
||||
|
||||
int get() |
||||
{ |
||||
if ( m >= n ) |
||||
return -1; |
||||
|
||||
Redo: |
||||
// We can't use `rand': different C libraries might provide
|
||||
// different implementations of this function. As a replacement,
|
||||
// we use a 32bit version of the `xorshift' algorithm.
|
||||
r ^= r << 13; |
||||
r ^= r >> 17; |
||||
r ^= r << 5; |
||||
|
||||
double U = double( r ) / UINT32_MAX; |
||||
|
||||
if ( ( N - t ) * U >= ( n - m ) ) |
||||
{ |
||||
t++; |
||||
goto Redo; |
||||
} |
||||
|
||||
t++; |
||||
m++; |
||||
|
||||
return t; |
||||
} |
||||
}; |
||||
|
||||
|
||||
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 ( !FT_HAS_MULTIPLE_MASTERS( face ) ) |
||||
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, |
||||
FT_UInt( 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 up to 20 arbitrarily selected faces
|
||||
// from index range [0;num-faces-1]
|
||||
long max_face_cnt = num_faces < 20 |
||||
? num_faces |
||||
: 20; |
||||
|
||||
Random faces_pool( (int)max_face_cnt, (int)num_faces ); |
||||
|
||||
for ( long face_cnt = 0; |
||||
face_cnt < max_face_cnt; |
||||
face_cnt++ ) |
||||
{ |
||||
long face_index = faces_pool.get() - 1; |
||||
|
||||
// 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 ); |
||||
|
||||
// loop over the face without instance (index 0)
|
||||
// and up to 20 arbitrarily selected instances
|
||||
// from index range [1;num_instances]
|
||||
long max_instance_cnt = num_instances < 20 |
||||
? num_instances |
||||
: 20; |
||||
|
||||
Random instances_pool( (int)max_instance_cnt, (int)num_instances ); |
||||
|
||||
for ( long instance_cnt = 0; |
||||
instance_cnt <= max_instance_cnt; |
||||
instance_cnt++ ) |
||||
{ |
||||
long instance_index = 0; |
||||
|
||||
if ( !instance_cnt ) |
||||
{ |
||||
if ( FT_New_Memory_Face( library, |
||||
files[0].data(), |
||||
(FT_Long)files[0].size(), |
||||
face_index, |
||||
&face ) ) |
||||
continue; |
||||
} |
||||
else |
||||
{ |
||||
instance_index = instances_pool.get(); |
||||
|
||||
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 an arbitrary size for outlines
|
||||
// and up to ten arbitrarily selected bitmap strike sizes
|
||||
// from the range [0;num_fixed_sizes - 1]
|
||||
int max_size_cnt = face->num_fixed_sizes < 10 |
||||
? face->num_fixed_sizes |
||||
: 10; |
||||
|
||||
Random sizes_pool( max_size_cnt, face->num_fixed_sizes ); |
||||
|
||||
for ( int size_cnt = 0; |
||||
size_cnt <= max_size_cnt; |
||||
size_cnt++ ) |
||||
{ |
||||
FT_Int32 flags = load_flags; |
||||
|
||||
int size_index = 0; |
||||
|
||||
if ( !size_cnt ) |
||||
{ |
||||
// set up 20pt at 72dpi as an arbitrary size
|
||||
if ( FT_Set_Char_Size( face, 20 * 64, 20 * 64, 72, 72 ) ) |
||||
continue; |
||||
flags |= FT_LOAD_NO_BITMAP; |
||||
} |
||||
else |
||||
{ |
||||
// bitmap strikes are not active for font variations
|
||||
if ( instance_index ) |
||||
continue; |
||||
|
||||
size_index = sizes_pool.get() - 1; |
||||
|
||||
if ( FT_Select_Size( face, size_index ) ) |
||||
continue; |
||||
flags |= FT_LOAD_COLOR; |
||||
} |
||||
|
||||
// test MM interface only for a face without a selected instance
|
||||
// and without a selected bitmap strike
|
||||
if ( !instance_index && !size_cnt ) |
||||
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
|
@ -1,314 +0,0 @@ |
||||
// ftmutator.cc
|
||||
//
|
||||
// A custom fuzzer mutator to test for FreeType with libFuzzer.
|
||||
//
|
||||
// Copyright 2015-2018 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.
|
||||
|
||||
|
||||
// Since `tar' is not a valid format for input to FreeType, treat any input
|
||||
// that looks like `tar' as multiple files and mutate them separately.
|
||||
//
|
||||
// In the future, a variation of this may be used to guide mutation on a
|
||||
// logically higher level.
|
||||
|
||||
|
||||
// we use `unique_ptr', `decltype', and other gimmicks defined since C++11
|
||||
#if __cplusplus < 201103L |
||||
# error "a C++11 compiler is needed" |
||||
#endif |
||||
|
||||
#include <cstdint> |
||||
#include <cassert> |
||||
#include <cstdio> |
||||
#include <cstdlib> |
||||
#include <cstddef> |
||||
#include <cstring> |
||||
#include <iostream> |
||||
|
||||
#include <memory> |
||||
#include <vector> |
||||
|
||||
#include <archive.h> |
||||
#include <archive_entry.h> |
||||
|
||||
#include "FuzzerInterface.h" |
||||
|
||||
|
||||
using namespace std; |
||||
|
||||
|
||||
// This function should be defined by `ftfuzzer.cc'.
|
||||
extern "C" int |
||||
LLVMFuzzerTestOneInput( const uint8_t* Data, |
||||
size_t Size ); |
||||
|
||||
|
||||
static void |
||||
check_result( struct archive* a, |
||||
int r ) |
||||
{ |
||||
if ( r == ARCHIVE_OK ) |
||||
return; |
||||
|
||||
const char* m = archive_error_string( a ); |
||||
write( 1, m, strlen( m ) ); |
||||
exit( 1 ); |
||||
} |
||||
|
||||
|
||||
static int |
||||
archive_read_entry_data( struct archive *ar, |
||||
vector<uint8_t> *vw ) |
||||
{ |
||||
int r; |
||||
const uint8_t* 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<uint8_t>> |
||||
parse_data( const uint8_t* data, |
||||
size_t size ) |
||||
{ |
||||
struct archive_entry* entry; |
||||
int r; |
||||
vector<vector<uint8_t>> 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<uint8_t> entry_data; |
||||
r = archive_read_entry_data( a.get(), &entry_data ); |
||||
if ( entry_data.size() == 0 ) |
||||
continue; |
||||
|
||||
files.push_back( move( entry_data ) ); |
||||
if ( r != ARCHIVE_OK ) |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return files; |
||||
} |
||||
|
||||
|
||||
class FTFuzzer |
||||
: public fuzzer::UserSuppliedFuzzer |
||||
{ |
||||
|
||||
public: |
||||
FTFuzzer( fuzzer::FuzzerRandomBase* Rand ) |
||||
: fuzzer::UserSuppliedFuzzer( Rand ) {} |
||||
|
||||
|
||||
int |
||||
TargetFunction( const uint8_t* Data, |
||||
size_t Size ) |
||||
{ |
||||
return LLVMFuzzerTestOneInput( Data, Size ); |
||||
} |
||||
|
||||
|
||||
// Custom mutator.
|
||||
virtual size_t |
||||
Mutate( uint8_t* Data, |
||||
size_t Size, |
||||
size_t MaxSize ) |
||||
{ |
||||
vector<vector<uint8_t>> files = parse_data( Data, Size ); |
||||
|
||||
// If the file was not recognized as a tar file, treat it as non-tar.
|
||||
if ( files.size() == 0 ) |
||||
return fuzzer::UserSuppliedFuzzer::Mutate( Data, Size, MaxSize ); |
||||
|
||||
// This is somewhat `white box' on tar. The tar format uses 512 byte
|
||||
// blocks. One block as header for each file, two empty blocks of 0's
|
||||
// at the end. File data is padded to fill its last block.
|
||||
size_t used_blocks = files.size() + 2; |
||||
for ( const auto& file : files ) |
||||
used_blocks += ( file.size() + 511 ) / 512; |
||||
|
||||
size_t max_blocks = MaxSize / 512; |
||||
|
||||
// If the input is big, it will need to be downsized. If the original
|
||||
// tar file was too big, it may have been clipped to fit. In this
|
||||
// case it may not be possible to properly write out the data, as
|
||||
// there may not be enough space for the trailing two blocks. Start
|
||||
// dropping file data or files from the end.
|
||||
for ( size_t i = files.size(); |
||||
i-- > 1 && used_blocks > max_blocks; ) |
||||
{ |
||||
size_t blocks_to_free = used_blocks - max_blocks; |
||||
size_t blocks_currently_used_by_file_data = |
||||
( files[i].size() + 511 ) / 512; |
||||
|
||||
if ( blocks_currently_used_by_file_data >= blocks_to_free ) |
||||
{ |
||||
files[i].resize( ( blocks_currently_used_by_file_data - |
||||
blocks_to_free ) * 512 ); |
||||
used_blocks -= blocks_to_free; |
||||
continue; |
||||
} |
||||
|
||||
files.pop_back(); |
||||
used_blocks -= blocks_currently_used_by_file_data + 1; |
||||
} |
||||
|
||||
// If we get down to one file, don't use tar.
|
||||
if ( files.size() == 1 ) |
||||
{ |
||||
memcpy( Data, files[0].data(), files[0].size() ); |
||||
return fuzzer::UserSuppliedFuzzer::Mutate( Data, |
||||
files[0].size(), |
||||
MaxSize ); |
||||
} |
||||
|
||||
size_t free_blocks = max_blocks - used_blocks; |
||||
|
||||
// Allow each file to use up as much of the currently available space
|
||||
// it can. If it uses or gives up blocks, add them or remove them
|
||||
// from the pool.
|
||||
for ( auto&& file : files ) |
||||
{ |
||||
size_t blocks_currently_used_by_file = ( file.size() + 511 ) / 512; |
||||
size_t blocks_available = blocks_currently_used_by_file + |
||||
free_blocks; |
||||
size_t max_size = blocks_available * 512; |
||||
size_t data_size = file.size(); |
||||
|
||||
file.resize( max_size ); |
||||
file.resize( fuzzer::UserSuppliedFuzzer::Mutate( file.data(), |
||||
data_size, |
||||
max_size ) ); |
||||
|
||||
size_t blocks_now_used_by_file = ( file.size() + 511 ) / 512; |
||||
free_blocks = free_blocks + |
||||
blocks_currently_used_by_file - |
||||
blocks_now_used_by_file; |
||||
} |
||||
|
||||
unique_ptr<struct archive, |
||||
decltype ( archive_write_free )*> a( archive_write_new(), |
||||
archive_write_free ); |
||||
|
||||
check_result( a.get(), archive_write_add_filter_none( a.get() ) ); |
||||
check_result( a.get(), archive_write_set_format_ustar( a.get() ) ); |
||||
|
||||
// `used' may not be correct until after the archive is closed.
|
||||
size_t used = 0xbadbeef; |
||||
check_result( a.get(), archive_write_open_memory( a.get(), |
||||
Data, |
||||
MaxSize, |
||||
&used ) ); |
||||
|
||||
{ |
||||
unique_ptr<struct archive, |
||||
decltype ( archive_write_close )*> a_open( a.get(), |
||||
archive_write_close ); |
||||
|
||||
int file_index = 0; |
||||
for ( const auto& file : files ) |
||||
{ |
||||
unique_ptr<struct archive_entry, |
||||
decltype ( archive_entry_free )*> |
||||
e( archive_entry_new2( a_open.get() ), |
||||
archive_entry_free ); |
||||
|
||||
char name_buffer[100]; |
||||
snprintf( name_buffer, 100, "file%d", file_index++ ); |
||||
|
||||
archive_entry_set_pathname( e.get(), name_buffer ); |
||||
archive_entry_set_size( e.get(), file.size() ); |
||||
archive_entry_set_filetype( e.get(), AE_IFREG ); |
||||
archive_entry_set_perm( e.get(), 0644 ); |
||||
|
||||
check_result( a_open.get(), |
||||
archive_write_header( a_open.get(), e.get() ) ); |
||||
archive_write_data( a_open.get(), file.data(), file.size() ); |
||||
check_result( a_open.get(), |
||||
archive_write_finish_entry( a_open.get() ) ); |
||||
} |
||||
} |
||||
|
||||
return used; |
||||
} |
||||
|
||||
|
||||
// Cross `Data1' and `Data2', write up to `MaxOutSize' bytes into `Out',
|
||||
// return the number of bytes written, which should be positive.
|
||||
virtual size_t |
||||
CrossOver( const uint8_t* Data1, |
||||
size_t Size1, |
||||
const uint8_t* Data2, |
||||
size_t Size2, |
||||
uint8_t* Out, |
||||
size_t MaxOutSize ) |
||||
{ |
||||
return fuzzer::UserSuppliedFuzzer::CrossOver( Data1, |
||||
Size1, |
||||
Data2, |
||||
Size2, |
||||
Out, |
||||
MaxOutSize ); |
||||
} |
||||
|
||||
}; // end of FTFuzzer class
|
||||
|
||||
|
||||
int |
||||
main( int argc, |
||||
char* *argv ) |
||||
{ |
||||
fuzzer::FuzzerRandomLibc Rand( 0 ); |
||||
FTFuzzer F( &Rand ); |
||||
|
||||
fuzzer::FuzzerDriver( argc, argv, F ); |
||||
} |
||||
|
||||
|
||||
// END
|
@ -1,129 +0,0 @@ |
||||
// rasterfuzzer.cc
|
||||
//
|
||||
// A fuzzing function to test FreeType's rasterizers with libFuzzer.
|
||||
//
|
||||
// Copyright 2016-2018 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.
|
||||
|
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <vector> |
||||
|
||||
|
||||
using namespace std; |
||||
|
||||
|
||||
#include <ft2build.h> |
||||
|
||||
#include FT_FREETYPE_H |
||||
#include FT_IMAGE_H |
||||
#include FT_OUTLINE_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; |
||||
|
||||
|
||||
extern "C" int |
||||
LLVMFuzzerTestOneInput( const uint8_t* data, |
||||
size_t size_ ) |
||||
{ |
||||
unsigned char pixels[4]; |
||||
|
||||
FT_Bitmap bitmap_mono = { |
||||
1, // rows
|
||||
1, // width
|
||||
4, // pitch
|
||||
pixels, // buffer
|
||||
2, // num_grays
|
||||
FT_PIXEL_MODE_MONO, // pixel_mode
|
||||
0, // palette_mode
|
||||
NULL // palette
|
||||
}; |
||||
|
||||
FT_Bitmap bitmap_gray = { |
||||
1, // rows
|
||||
1, // width
|
||||
4, // pitch
|
||||
pixels, // buffer
|
||||
256, // num_grays
|
||||
FT_PIXEL_MODE_GRAY, // pixel_mode
|
||||
0, // palette_mode
|
||||
NULL // palette
|
||||
}; |
||||
|
||||
const size_t vsize = sizeof ( FT_Vector ); |
||||
const size_t tsize = sizeof ( char ); |
||||
|
||||
// we use the input data for both points and tags
|
||||
short n_points = short( size_ / ( vsize + tsize ) ); |
||||
if ( n_points <= 2 ) |
||||
return 0; |
||||
|
||||
FT_Vector* points = reinterpret_cast<FT_Vector*>( |
||||
const_cast<uint8_t*>( |
||||
data ) ); |
||||
char* tags = reinterpret_cast<char*>( |
||||
const_cast<uint8_t*>( |
||||
data + size_t( n_points ) * vsize ) ); |
||||
|
||||
// to reduce the number of invalid outlines that are immediately
|
||||
// rejected in `FT_Outline_Render', limit values to 2^18 pixels
|
||||
// (i.e., 2^24 bits)
|
||||
for ( short i = 0; i < n_points; i++ ) |
||||
{ |
||||
if ( points[i].x == LONG_MIN ) |
||||
points[i].x = 0; |
||||
else if ( points[i].x < 0 ) |
||||
points[i].x = -( -points[i].x & 0xFFFFFF ) - 1; |
||||
else |
||||
points[i].x = ( points[i].x & 0xFFFFFF ) + 1; |
||||
|
||||
if ( points[i].y == LONG_MIN ) |
||||
points[i].y = 0; |
||||
else if ( points[i].y < 0 ) |
||||
points[i].y = -( -points[i].y & 0xFFFFFF ) - 1; |
||||
else |
||||
points[i].y = ( points[i].y & 0xFFFFFF ) + 1; |
||||
} |
||||
|
||||
short contours[1]; |
||||
contours[0] = n_points - 1; |
||||
|
||||
FT_Outline outline = |
||||
{ |
||||
1, // n_contours
|
||||
n_points, // n_points
|
||||
points, // points
|
||||
tags, // tags
|
||||
contours, // contours
|
||||
FT_OUTLINE_NONE // flags
|
||||
}; |
||||
|
||||
FT_Outline_Get_Bitmap( library, &outline, &bitmap_mono ); |
||||
FT_Outline_Get_Bitmap( library, &outline, &bitmap_gray ); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
// END
|
@ -1,58 +0,0 @@ |
||||
// runinput.cc
|
||||
//
|
||||
// A `main' function for fuzzers like `ftfuzzer.cc'.
|
||||
//
|
||||
// Copyright 2015-2018 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.
|
||||
|
||||
|
||||
#include <assert.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
|
||||
|
||||
extern "C" void |
||||
LLVMFuzzerTestOneInput( const uint8_t* data, |
||||
size_t size ); |
||||
|
||||
|
||||
unsigned char a[1 << 24]; |
||||
|
||||
|
||||
int |
||||
main( int argc, |
||||
char* *argv ) |
||||
{ |
||||
assert( argc >= 2 ); |
||||
|
||||
for ( int i = 1; i < argc; i++ ) |
||||
{ |
||||
fprintf( stderr, "%s\n", argv[i] ); |
||||
|
||||
FILE* f = fopen( argv[i], "r" ); |
||||
assert( f ); |
||||
|
||||
size_t n = fread( a, 1, sizeof ( a ), f ); |
||||
fclose( f ); |
||||
if ( !n ) |
||||
continue; |
||||
|
||||
unsigned char* b = (unsigned char*)malloc( n ); |
||||
memcpy( b, a, n ); |
||||
|
||||
LLVMFuzzerTestOneInput( b, n ); |
||||
|
||||
free( b ); |
||||
} |
||||
} |
||||
|
||||
|
||||
// END
|
Loading…
Reference in new issue