engine: first attempts on fuzzing the engine
This commit is contained in:
parent
204544f50f
commit
5aa6bfee85
7 changed files with 143 additions and 11 deletions
|
@ -566,4 +566,25 @@ void Test_RunImagelib( void )
|
||||||
Z_Free( rgb.buffer );
|
Z_Free( rgb.buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IMPLEMENT_IMAGELIB_FUZZ_TARGET( export, target ) \
|
||||||
|
int EXPORT export( const uint8_t *Data, size_t Size ) \
|
||||||
|
{ \
|
||||||
|
rgbdata_t *rgb; \
|
||||||
|
host.type = HOST_NORMAL; \
|
||||||
|
Memory_Init(); \
|
||||||
|
Image_Init(); \
|
||||||
|
if( target( "#internal", Data, Size )) \
|
||||||
|
{ \
|
||||||
|
rgb = ImagePack(); \
|
||||||
|
FS_FreeImage( rgb ); \
|
||||||
|
} \
|
||||||
|
Image_Shutdown(); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
IMPLEMENT_IMAGELIB_FUZZ_TARGET( Fuzz_Image_LoadBMP, Image_LoadBMP )
|
||||||
|
IMPLEMENT_IMAGELIB_FUZZ_TARGET( Fuzz_Image_LoadPNG, Image_LoadPNG )
|
||||||
|
IMPLEMENT_IMAGELIB_FUZZ_TARGET( Fuzz_Image_LoadDDS, Image_LoadDDS )
|
||||||
|
IMPLEMENT_IMAGELIB_FUZZ_TARGET( Fuzz_Image_LoadTGA, Image_LoadTGA )
|
||||||
|
|
||||||
#endif /* XASH_ENGINE_TESTS */
|
#endif /* XASH_ENGINE_TESTS */
|
||||||
|
|
|
@ -278,3 +278,25 @@ void FS_FreeStream( stream_t *stream )
|
||||||
|
|
||||||
stream->format->freefunc( stream );
|
stream->format->freefunc( stream );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if XASH_ENGINE_TESTS
|
||||||
|
|
||||||
|
#define IMPLEMENT_SOUNDLIB_FUZZ_TARGET( export, target ) \
|
||||||
|
int EXPORT export( const uint8_t *Data, size_t Size ) \
|
||||||
|
{ \
|
||||||
|
wavdata_t *wav; \
|
||||||
|
host.type = HOST_NORMAL; \
|
||||||
|
Memory_Init(); \
|
||||||
|
Sound_Init(); \
|
||||||
|
if( target( "#internal", Data, Size )) \
|
||||||
|
{ \
|
||||||
|
wav = SoundPack(); \
|
||||||
|
FS_FreeSound( wav ); \
|
||||||
|
} \
|
||||||
|
Sound_Shutdown(); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
IMPLEMENT_SOUNDLIB_FUZZ_TARGET( Fuzz_Sound_LoadMPG, Sound_LoadMPG )
|
||||||
|
IMPLEMENT_SOUNDLIB_FUZZ_TARGET( Fuzz_Sound_LoadWAV, Sound_LoadWAV )
|
||||||
|
#endif
|
||||||
|
|
|
@ -15,21 +15,20 @@ extern struct tests_stats_s tests_stats;
|
||||||
x; \
|
x; \
|
||||||
Msg( "Finished " #x "\n" )
|
Msg( "Finished " #x "\n" )
|
||||||
|
|
||||||
#define TASSERT( exp ) \
|
#define _TASSERT( exp, msg ) \
|
||||||
if(!( exp )) \
|
if( exp ) \
|
||||||
{ \
|
{ \
|
||||||
tests_stats.failed++; \
|
tests_stats.failed++; \
|
||||||
Msg( S_ERROR "assert failed at %s:%i\n", __FILE__, __LINE__ ); \
|
msg; \
|
||||||
} \
|
} \
|
||||||
else tests_stats.passed++;
|
else tests_stats.passed++;
|
||||||
|
|
||||||
|
#define TASSERT( exp ) \
|
||||||
|
_TASSERT( !(exp), Msg( S_ERROR "assert failed at %s:%i\n", __FILE__, __LINE__ ) )
|
||||||
|
#define TASSERT_EQi( val1, val2 ) \
|
||||||
|
_TASSERT( ( val1 ) != ( val2 ), Msg( S_ERROR "assert failed at %s:%i, \"%d\" != \"%d\"\n", __FILE__, __LINE__, #val1, #val2 ))
|
||||||
#define TASSERT_STR( str1, str2 ) \
|
#define TASSERT_STR( str1, str2 ) \
|
||||||
if( Q_strcmp(( str1 ), ( str2 ))) \
|
_TASSERT( Q_strcmp(( str1 ), ( str2 )), Msg( S_ERROR "assert failed at %s:%i, \"%s\" != \"%s\"\n", __FILE__, __LINE__, ( str1 ), ( str2 )))
|
||||||
{ \
|
|
||||||
tests_stats.failed++; \
|
|
||||||
Msg( S_ERROR "assert failed at %s:%i, \"%s\" != \"%s\"\n", __FILE__, __LINE__, ( str1 ), ( str2 )); \
|
|
||||||
} \
|
|
||||||
else tests_stats.passed++;
|
|
||||||
|
|
||||||
void Test_RunImagelib( void );
|
void Test_RunImagelib( void );
|
||||||
void Test_RunLibCommon( void );
|
void Test_RunLibCommon( void );
|
||||||
|
|
|
@ -32,6 +32,9 @@ def options(opt):
|
||||||
grp.add_option('--enable-engine-tests', action = 'store_true', dest = 'ENGINE_TESTS', default = False,
|
grp.add_option('--enable-engine-tests', action = 'store_true', dest = 'ENGINE_TESTS', default = False,
|
||||||
help = 'embed tests into the engine, jump into them by -runtests command line switch [default: %default]')
|
help = 'embed tests into the engine, jump into them by -runtests command line switch [default: %default]')
|
||||||
|
|
||||||
|
grp.add_option('--enable-engine-fuzz', action = 'store_true', dest = 'ENGINE_FUZZ', default = False,
|
||||||
|
help = 'add LLVM libFuzzer [default: %default]' )
|
||||||
|
|
||||||
opt.load('sdl2')
|
opt.load('sdl2')
|
||||||
|
|
||||||
def configure(conf):
|
def configure(conf):
|
||||||
|
@ -87,6 +90,10 @@ def configure(conf):
|
||||||
|
|
||||||
conf.env.ENGINE_TESTS = conf.options.ENGINE_TESTS
|
conf.env.ENGINE_TESTS = conf.options.ENGINE_TESTS
|
||||||
|
|
||||||
|
if conf.options.ENGINE_FUZZ:
|
||||||
|
conf.env.append_unique('CFLAGS', '-fsanitize=fuzzer-no-link')
|
||||||
|
conf.env.append_unique('LINKFLAGS', '-fsanitize=fuzzer')
|
||||||
|
|
||||||
conf.define_cond('XASH_ENGINE_TESTS', conf.env.ENGINE_TESTS)
|
conf.define_cond('XASH_ENGINE_TESTS', conf.env.ENGINE_TESTS)
|
||||||
conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING)
|
conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING)
|
||||||
conf.define_cond('XASH_CUSTOM_SWAP', conf.options.CUSTOM_SWAP)
|
conf.define_cond('XASH_CUSTOM_SWAP', conf.options.CUSTOM_SWAP)
|
||||||
|
|
34
utils/run-fuzzer/run-fuzzer.c
Normal file
34
utils/run-fuzzer/run-fuzzer.c
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if !defined LIB || !defined FUNC
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int (*FuzzFunc)(const char *Data, size_t Size);
|
||||||
|
|
||||||
|
void *handle = NULL;
|
||||||
|
FuzzFunc f = NULL;
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput( const char *Data, size_t Size )
|
||||||
|
{
|
||||||
|
if( !handle )
|
||||||
|
handle = dlopen( LIB, RTLD_NOW );
|
||||||
|
|
||||||
|
if( handle )
|
||||||
|
{
|
||||||
|
if( !f )
|
||||||
|
f = dlsym( handle, FUNC );
|
||||||
|
|
||||||
|
if( f )
|
||||||
|
{
|
||||||
|
return f( Data, Size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( stderr, "Fail: %s\n", dlerror() );
|
||||||
|
|
||||||
|
abort();
|
||||||
|
return 0;
|
||||||
|
}
|
40
utils/run-fuzzer/wscript
Normal file
40
utils/run-fuzzer/wscript
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
# a1batross, mittorn, 2018
|
||||||
|
|
||||||
|
def options(opt):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def configure(conf):
|
||||||
|
if conf.options.BUILD_TYPE != 'sanitize':
|
||||||
|
conf.fatal('useless without -T sanitize')
|
||||||
|
|
||||||
|
if conf.env.COMPILER_CC != 'clang':
|
||||||
|
conf.fatal('only clang is supported')
|
||||||
|
|
||||||
|
conf.env.append_unique('CFLAGS', '-fsanitize=fuzzer')
|
||||||
|
conf.env.append_unique('LINKFLAGS', '-fsanitize=fuzzer')
|
||||||
|
|
||||||
|
def add_runner_target(bld, lib, func):
|
||||||
|
source = bld.path.ant_glob('*.c')
|
||||||
|
includes = '.'
|
||||||
|
libs = [ 'DL' ]
|
||||||
|
|
||||||
|
bld(
|
||||||
|
source = source,
|
||||||
|
target = 'run-fuzzer-' + func,
|
||||||
|
features = 'c cprogram',
|
||||||
|
includes = includes,
|
||||||
|
use = libs,
|
||||||
|
defines = ['FUNC="Fuzz_' + func + '"', 'LIB="' + lib + '"'],
|
||||||
|
install_path = bld.env.BINDIR,
|
||||||
|
subsystem = bld.env.CONSOLE_SUBSYSTEM
|
||||||
|
)
|
||||||
|
|
||||||
|
def build(bld):
|
||||||
|
add_runner_target(bld, 'libxash.so', 'Sound_LoadMPG')
|
||||||
|
add_runner_target(bld, 'libxash.so', 'Sound_LoadWAV')
|
||||||
|
add_runner_target(bld, 'libxash.so', 'Image_LoadBMP')
|
||||||
|
add_runner_target(bld, 'libxash.so', 'Image_LoadPNG')
|
||||||
|
add_runner_target(bld, 'libxash.so', 'Image_LoadDDS')
|
||||||
|
add_runner_target(bld, 'libxash.so', 'Image_LoadTGA')
|
13
wscript
13
wscript
|
@ -20,12 +20,13 @@ class Subproject:
|
||||||
ignore = False # if true will be ignored, set by user request
|
ignore = False # if true will be ignored, set by user request
|
||||||
mandatory = False
|
mandatory = False
|
||||||
|
|
||||||
def __init__(self, name, dedicated=True, singlebin=False, mandatory = False, utility = False):
|
def __init__(self, name, dedicated=True, singlebin=False, mandatory = False, utility = False, fuzzer = False):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.dedicated = dedicated
|
self.dedicated = dedicated
|
||||||
self.singlebin = singlebin
|
self.singlebin = singlebin
|
||||||
self.mandatory = mandatory
|
self.mandatory = mandatory
|
||||||
self.utility = utility
|
self.utility = utility
|
||||||
|
self.fuzzer = fuzzer
|
||||||
|
|
||||||
def is_enabled(self, ctx):
|
def is_enabled(self, ctx):
|
||||||
if not self.mandatory:
|
if not self.mandatory:
|
||||||
|
@ -47,6 +48,9 @@ class Subproject:
|
||||||
if self.utility and not ctx.env.ENABLE_UTILS:
|
if self.utility and not ctx.env.ENABLE_UTILS:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if self.fuzzer and not ctx.env.ENABLE_FUZZER:
|
||||||
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
SUBDIRS = [
|
SUBDIRS = [
|
||||||
|
@ -60,7 +64,8 @@ SUBDIRS = [
|
||||||
Subproject('stub/client'),
|
Subproject('stub/client'),
|
||||||
Subproject('dllemu'),
|
Subproject('dllemu'),
|
||||||
Subproject('engine', dedicated=False),
|
Subproject('engine', dedicated=False),
|
||||||
Subproject('utils/mdldec', utility=True)
|
Subproject('utils/mdldec', utility=True),
|
||||||
|
Subproject('utils/run-fuzzer', fuzzer=True)
|
||||||
]
|
]
|
||||||
|
|
||||||
def subdirs():
|
def subdirs():
|
||||||
|
@ -98,6 +103,9 @@ def options(opt):
|
||||||
grp.add_option('--enable-utils', action = 'store_true', dest = 'ENABLE_UTILS', default = False,
|
grp.add_option('--enable-utils', action = 'store_true', dest = 'ENABLE_UTILS', default = False,
|
||||||
help = 'enable building various development utilities [default: %default]')
|
help = 'enable building various development utilities [default: %default]')
|
||||||
|
|
||||||
|
grp.add_option('--enable-fuzzer', action = 'store_true', dest = 'ENABLE_FUZZER', default = False,
|
||||||
|
help = 'enable building libFuzzer runner [default: %default]' )
|
||||||
|
|
||||||
opt.load('compiler_optimizations subproject')
|
opt.load('compiler_optimizations subproject')
|
||||||
|
|
||||||
for i in SUBDIRS:
|
for i in SUBDIRS:
|
||||||
|
@ -245,6 +253,7 @@ def configure(conf):
|
||||||
conf.define('STDINT_H', 'pstdint.h')
|
conf.define('STDINT_H', 'pstdint.h')
|
||||||
|
|
||||||
conf.env.ENABLE_UTILS = conf.options.ENABLE_UTILS
|
conf.env.ENABLE_UTILS = conf.options.ENABLE_UTILS
|
||||||
|
conf.env.ENABLE_FUZZER = conf.options.ENABLE_FUZZER
|
||||||
conf.env.DEDICATED = conf.options.DEDICATED
|
conf.env.DEDICATED = conf.options.DEDICATED
|
||||||
conf.env.SINGLE_BINARY = conf.options.SINGLE_BINARY or conf.env.DEDICATED
|
conf.env.SINGLE_BINARY = conf.options.SINGLE_BINARY or conf.env.DEDICATED
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue