mirror of
https://github.com/boostorg/json.git
synced 2026-01-19 16:22:20 +00:00
217 lines
5.5 KiB
Plaintext
217 lines
5.5 KiB
Plaintext
#
|
|
# Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
|
# Copyright (c) 2019 Paul Dreik
|
|
# Copyright (c) 2021 Dmitry Arkhipov (grisumbras@gmail.com)
|
|
#
|
|
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
#
|
|
# Official repository: https://github.com/boostorg/json
|
|
#
|
|
|
|
|
|
import common ;
|
|
import link ;
|
|
import os ;
|
|
import path ;
|
|
import property ;
|
|
import sequence ;
|
|
import testing ;
|
|
|
|
|
|
# set the maximum size of the input, to avoid
|
|
# big inputs which blow up the corpus size
|
|
.MAXLEN = [ os.environ MAXLEN ] ;
|
|
.MAXLEN ?= -max_len=4000 ;
|
|
|
|
# set a timelimit (you may want to adjust this if you run locally)
|
|
.MAXTIME = [ os.environ MAXTIME ] ;
|
|
.MAXTIME ?= -max_total_time=30 ;
|
|
|
|
# If doing fuzzing locally (not in CI), adjust this to utilize more
|
|
# of your cpu.
|
|
#JOBS="-jobs=32"
|
|
.JOBS = [ os.environ JOBS ] ;
|
|
|
|
# make sure ubsan stops in case anything is found
|
|
.UBSAN_OPTIONS = [
|
|
common.variable-setting-command UBSAN_OPTIONS : halt_on_error=1
|
|
] ;
|
|
|
|
local corpus.tar = [ glob-ex . : corpus.tar ] ;
|
|
local test-corpus ;
|
|
if $(corpus.tar)
|
|
{
|
|
# if an old corpus exists, use it
|
|
make old-corpus
|
|
: $(corpus.tar)
|
|
: @untar-corpus
|
|
: <location>oldcorpus
|
|
;
|
|
explicit old-corpus ;
|
|
}
|
|
else
|
|
{
|
|
test-corpus = [ glob-tree-ex ../test : *.json ] ;
|
|
}
|
|
|
|
local old-runs = [ SORT [ glob-tree-ex old_crashes : * ] ] ;
|
|
make old_crashes : : @mkdir : <location>. ;
|
|
explicit old_crashes ;
|
|
|
|
local variants = basic_parser parse parser direct_parse ;
|
|
for local variant in basic_parser parse parser direct_parse
|
|
{
|
|
local $(variant)-runs ;
|
|
local fuzzer = fuzzer_$(variant) ;
|
|
exe $(fuzzer)
|
|
: fuzz_$(variant).cpp /boost/json//json_sources
|
|
: requirements
|
|
<toolset>clang
|
|
<conditional>@fuzzer-props
|
|
;
|
|
|
|
# make sure the old crashes pass without problems
|
|
if $(old-runs)
|
|
{
|
|
run $(fuzzer)
|
|
: target-name $(variant)-run-crashes
|
|
: input-files $(old-runs)
|
|
;
|
|
explicit $(variant)-run-crashes ;
|
|
$(variant)-runs += $(variant)-run-crashes ;
|
|
}
|
|
|
|
local old-corpus-deps ;
|
|
if $(corpus.tar)
|
|
{
|
|
old-corpus-deps = old-corpus ;
|
|
}
|
|
else
|
|
{
|
|
# make an initial corpus from the test data already in the repo
|
|
for file in $(test-corpus)
|
|
{
|
|
local copied = $(variant)/$(file:D=) ;
|
|
make $(copied) : $(file) : common.copy : <location>oldcorpus ;
|
|
explicit $(copied) ;
|
|
old-corpus-deps += $(copied) ;
|
|
}
|
|
}
|
|
make oldcorpus/$(variant)
|
|
: $(old-corpus-deps)
|
|
: @mkdir
|
|
: <location>.
|
|
;
|
|
explicit oldcorpus/$(variant) ;
|
|
|
|
# run the fuzzer for a short while
|
|
make out/$(variant)
|
|
: $(fuzzer)
|
|
oldcorpus/$(variant)
|
|
old_crashes
|
|
: @run-fuzzer
|
|
: <location>.
|
|
<flags>$(.MAXTIME)
|
|
<flags>$(.MAXLEN)
|
|
<flags>$(.JOBS)
|
|
;
|
|
$(variant)-runs += out/$(variant) ;
|
|
|
|
# minimize the corpus
|
|
make cmin/$(variant)
|
|
: $(fuzzer)
|
|
out/$(variant)
|
|
oldcorpus/$(variant)
|
|
old_crashes
|
|
: @run-fuzzer
|
|
: <location>.
|
|
<flags>-merge=1
|
|
<flags>$(.MAXLEN)
|
|
;
|
|
$(variant)-runs += cmin/$(variant) ;
|
|
|
|
alias $(variant)-run : $($(variant)-runs) ;
|
|
explicit $($(variant)-runs) ;
|
|
}
|
|
|
|
alias run : $(variants)-run ;
|
|
explicit run $(variants)-run ;
|
|
|
|
|
|
rule mkdir ( target : source * : props * )
|
|
{
|
|
local dir = [ path.make [ on $(target) return $(LOCATE) ] ] ;
|
|
dir = [ path.join $(dir) $(target:G=) ] ;
|
|
common.MkDir $(dir) ;
|
|
}
|
|
|
|
rule fuzzer-props ( props * )
|
|
{
|
|
local toolset = [ property.select toolset : $(props) ] ;
|
|
if clang = $(toolset:G=)
|
|
{
|
|
return
|
|
<debug-symbols>on
|
|
<optimization>speed
|
|
<address-sanitizer>on
|
|
<undefined-sanitizer>norecover
|
|
<cxxflags>-fsanitize=fuzzer
|
|
<linkflags>-fsanitize=fuzzer
|
|
# explicitly set BOOST_JSON_STACK_BUFFER_SIZE small so interesting
|
|
# code paths are taken also for small inputs
|
|
# (see https://github.com/boostorg/json/issues/333)
|
|
<define>BOOST_JSON_STACK_BUFFER_SIZE=64
|
|
;
|
|
}
|
|
else
|
|
{
|
|
return <build>no ;
|
|
}
|
|
}
|
|
|
|
|
|
rule run-fuzzer ( target : sources * : props * )
|
|
{
|
|
local flags = [ property.select flags : $(props) ] ;
|
|
FLAGS on $(target) = $(flags:G=) ;
|
|
|
|
LOG on $(target) = [ path.native [ path.join $(target) _log ] ] ;
|
|
|
|
local dir = [ path.make [ on $(target) return $(LOCATE) ] ] ;
|
|
dir = $(dir)/$(target:G=) ;
|
|
common.MkDir $(dir) ;
|
|
DEPENDS $(target) : $(dir) ;
|
|
|
|
LOG on $(target) = [ path.native [ path.join $(dir) _log ] ] ;
|
|
}
|
|
|
|
.SET_STATUS = [ modules.peek testing : .SET_STATUS ] ;
|
|
.STATUS = [ modules.peek testing : .STATUS ] ;
|
|
.RUN_OUTPUT_NL = [ modules.peek testing : .RUN_OUTPUT_NL ] ;
|
|
.STATUS_NOT_0 = [ modules.peek testing : .STATUS_NOT_0 ] ;
|
|
.CATENATE = [ modules.peek testing : .CATENATE ] ;
|
|
.ENDIF = [ modules.peek testing : .ENDIF ] ;
|
|
.NULL_OUT = [ modules.peek common : NULL_OUT ] ;
|
|
.RM = [ common.rm-command ] ;
|
|
actions run-fuzzer
|
|
{
|
|
$(.UBSAN_OPTIONS)
|
|
$(>[1]) $(<) $(>[2-]) $(FLAGS) > "$(LOG)" 2>&1
|
|
$(.SET_STATUS)
|
|
if $(.STATUS_NOT_0)
|
|
echo ====== BEGIN OUTPUT ======
|
|
$(.CATENATE) "$(LOG)"
|
|
echo ====== END OUTPUT ======
|
|
$(RM) $(LOG) $(.NULL_OUT)
|
|
exit 1
|
|
$(.ENDIF)
|
|
}
|
|
|
|
.TOUCH_FILE = [ common.file-touch-command ] ;
|
|
actions untar-corpus
|
|
{
|
|
tar xf $(>) -C $(<:D)
|
|
$(.TOUCH_FILE) $(<)
|
|
}
|