2
0
mirror of https://github.com/boostorg/json.git synced 2026-01-19 16:22:20 +00:00
Files
json/fuzzing/Jamfile
2025-10-24 16:22:05 +03:00

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) $(<)
}