aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:11:54 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:11:54 +0000
commitcdf4f3055e964bb585f294cf77cb549ead82783f (patch)
tree7bceeca766b3fbe491245bc926a083f78c35d1de /lib
parent625108084a3ec7c19c7745004c5af0ed7aa417a9 (diff)
downloadsrc-cdf4f3055e964bb585f294cf77cb549ead82783f.tar.gz
src-cdf4f3055e964bb585f294cf77cb549ead82783f.zip
Vendor import of compiler-rt trunk r321017:vendor/compiler-rt/compiler-rt-trunk-r321017
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=326943 svn path=/vendor/compiler-rt/compiler-rt-trunk-r321017/; revision=326944; tag=vendor/compiler-rt/compiler-rt-trunk-r321017
Diffstat (limited to 'lib')
-rw-r--r--lib/BlocksRuntime/Block.h2
-rw-r--r--lib/BlocksRuntime/Block_private.h2
-rw-r--r--lib/CMakeLists.txt6
-rw-r--r--lib/asan/CMakeLists.txt26
-rw-r--r--lib/asan/asan_activation.cc7
-rw-r--r--lib/asan/asan_allocator.cc84
-rw-r--r--lib/asan/asan_allocator.h11
-rw-r--r--lib/asan/asan_descriptions.cc39
-rw-r--r--lib/asan/asan_descriptions.h11
-rw-r--r--lib/asan/asan_errors.cc150
-rw-r--r--lib/asan/asan_errors.h82
-rw-r--r--lib/asan/asan_fake_stack.cc8
-rw-r--r--lib/asan/asan_flags.cc7
-rw-r--r--lib/asan/asan_flags.inc9
-rw-r--r--lib/asan/asan_fuchsia.cc218
-rw-r--r--lib/asan/asan_globals.cc7
-rw-r--r--lib/asan/asan_init_version.h7
-rw-r--r--lib/asan/asan_interceptors.cc191
-rw-r--r--lib/asan/asan_interceptors.h54
-rw-r--r--lib/asan/asan_interceptors_memintrinsics.cc44
-rw-r--r--lib/asan/asan_interceptors_memintrinsics.h148
-rw-r--r--lib/asan/asan_internal.h7
-rw-r--r--lib/asan/asan_linux.cc81
-rw-r--r--lib/asan/asan_malloc_linux.cc52
-rw-r--r--lib/asan/asan_mapping.h32
-rw-r--r--lib/asan/asan_memory_profile.cc3
-rw-r--r--lib/asan/asan_new_delete.cc102
-rw-r--r--lib/asan/asan_poisoning.cc2
-rw-r--r--lib/asan/asan_poisoning.h7
-rw-r--r--lib/asan/asan_posix.cc56
-rw-r--r--lib/asan/asan_premap_shadow.cc79
-rw-r--r--lib/asan/asan_premap_shadow.h30
-rw-r--r--lib/asan/asan_report.cc151
-rw-r--r--lib/asan/asan_report.h6
-rw-r--r--lib/asan/asan_rtl.cc147
-rw-r--r--lib/asan/asan_scariness_score.h2
-rw-r--r--lib/asan/asan_shadow_setup.cc165
-rw-r--r--lib/asan/asan_stack.h52
-rw-r--r--lib/asan/asan_thread.cc58
-rw-r--r--lib/asan/asan_thread.h35
-rw-r--r--lib/asan/asan_win.cc4
-rwxr-xr-xlib/asan/scripts/asan_device_setup37
-rwxr-xr-xlib/asan/scripts/asan_symbolize.py4
-rw-r--r--lib/asan/tests/CMakeLists.txt244
-rw-r--r--lib/asan/tests/asan_asm_test.cc3
-rw-r--r--lib/asan/tests/asan_interface_test.cc33
-rw-r--r--lib/asan/tests/asan_str_test.cc6
-rw-r--r--lib/asan/tests/asan_test.cc30
-rw-r--r--lib/asan/tests/asan_test_utils.h2
-rw-r--r--lib/builtins/CMakeLists.txt80
-rw-r--r--lib/builtins/adddf3.c5
-rw-r--r--lib/builtins/addsf3.c5
-rw-r--r--lib/builtins/arm/aeabi_cdcmp.S9
-rw-r--r--lib/builtins/arm/aeabi_cfcmp.S9
-rw-r--r--lib/builtins/arm/aeabi_idivmod.S8
-rw-r--r--lib/builtins/arm/aeabi_memcmp.S6
-rw-r--r--lib/builtins/arm/aeabi_memcpy.S6
-rw-r--r--lib/builtins/arm/aeabi_memmove.S6
-rw-r--r--lib/builtins/arm/aeabi_memset.S13
-rw-r--r--lib/builtins/arm/aeabi_uidivmod.S6
-rw-r--r--lib/builtins/arm/bswapdi2.S8
-rw-r--r--lib/builtins/arm/bswapsi2.S8
-rw-r--r--lib/builtins/arm/clzdi2.S9
-rw-r--r--lib/builtins/arm/clzsi2.S8
-rw-r--r--lib/builtins/arm/comparesf2.S28
-rw-r--r--lib/builtins/arm/divmodsi4.S8
-rw-r--r--lib/builtins/arm/divsi3.S18
-rw-r--r--lib/builtins/arm/modsi3.S8
-rw-r--r--lib/builtins/arm/udivmodsi4.S13
-rw-r--r--lib/builtins/arm/udivsi3.S32
-rw-r--r--lib/builtins/arm/umodsi3.S12
-rw-r--r--lib/builtins/ashldi3.c5
-rw-r--r--lib/builtins/ashrdi3.c5
-rw-r--r--lib/builtins/assembly.h56
-rw-r--r--lib/builtins/clear_cache.c31
-rw-r--r--lib/builtins/comparedf2.c5
-rw-r--r--lib/builtins/comparesf2.c5
-rw-r--r--lib/builtins/cpu_model.c12
-rw-r--r--lib/builtins/divdf3.c5
-rw-r--r--lib/builtins/divsf3.c5
-rw-r--r--lib/builtins/divsi3.c5
-rw-r--r--lib/builtins/emutls.c14
-rw-r--r--lib/builtins/enable_execute_stack.c2
-rw-r--r--lib/builtins/extendhfsf2.c5
-rw-r--r--lib/builtins/extendsfdf2.c5
-rw-r--r--lib/builtins/fixdfdi.c12
-rw-r--r--lib/builtins/fixdfsi.c5
-rw-r--r--lib/builtins/fixsfdi.c12
-rw-r--r--lib/builtins/fixsfsi.c5
-rw-r--r--lib/builtins/fixunsdfdi.c12
-rw-r--r--lib/builtins/fixunsdfsi.c5
-rw-r--r--lib/builtins/fixunssfdi.c12
-rw-r--r--lib/builtins/fixunssfsi.c5
-rw-r--r--lib/builtins/floatdidf.c5
-rw-r--r--lib/builtins/floatdisf.c5
-rw-r--r--lib/builtins/floatsidf.c5
-rw-r--r--lib/builtins/floatsisf.c5
-rw-r--r--lib/builtins/floatundidf.c5
-rw-r--r--lib/builtins/floatundisf.c5
-rw-r--r--lib/builtins/floatunsidf.c5
-rw-r--r--lib/builtins/floatunsisf.c5
-rw-r--r--lib/builtins/int_endianness.h4
-rw-r--r--lib/builtins/int_lib.h4
-rw-r--r--lib/builtins/lshrdi3.c5
-rw-r--r--lib/builtins/muldf3.c5
-rw-r--r--lib/builtins/muldi3.c5
-rw-r--r--lib/builtins/mulsf3.c5
-rw-r--r--lib/builtins/negdf2.c5
-rw-r--r--lib/builtins/negsf2.c5
-rw-r--r--lib/builtins/subdf3.c5
-rw-r--r--lib/builtins/subsf3.c5
-rw-r--r--lib/builtins/truncdfhf2.c5
-rw-r--r--lib/builtins/truncdfsf2.c5
-rw-r--r--lib/builtins/truncsfhf2.c5
-rw-r--r--lib/builtins/udivsi3.c5
-rw-r--r--lib/cfi/CMakeLists.txt60
-rw-r--r--lib/cfi/cfi.cc2
-rw-r--r--lib/cfi/cfi_blacklist.txt16
-rw-r--r--lib/dfsan/dfsan.cc1
-rw-r--r--lib/esan/esan_sideline.h4
-rw-r--r--lib/esan/esan_sideline_linux.cpp3
-rw-r--r--lib/esan/working_set_posix.cpp7
-rw-r--r--lib/fuzzer/CMakeLists.txt80
-rw-r--r--lib/fuzzer/FuzzerClangCounters.cpp49
-rw-r--r--lib/fuzzer/FuzzerCommand.h180
-rw-r--r--lib/fuzzer/FuzzerCorpus.h302
-rw-r--r--lib/fuzzer/FuzzerCrossOver.cpp52
-rw-r--r--lib/fuzzer/FuzzerDefs.h167
-rw-r--r--lib/fuzzer/FuzzerDictionary.h127
-rw-r--r--lib/fuzzer/FuzzerDriver.cpp767
-rw-r--r--lib/fuzzer/FuzzerExtFunctions.def47
-rw-r--r--lib/fuzzer/FuzzerExtFunctions.h35
-rw-r--r--lib/fuzzer/FuzzerExtFunctionsDlsym.cpp52
-rw-r--r--lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp62
-rw-r--r--lib/fuzzer/FuzzerExtFunctionsWeak.cpp54
-rw-r--r--lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp56
-rw-r--r--lib/fuzzer/FuzzerExtraCounters.cpp41
-rw-r--r--lib/fuzzer/FuzzerFlags.def150
-rw-r--r--lib/fuzzer/FuzzerIO.cpp129
-rw-r--r--lib/fuzzer/FuzzerIO.h85
-rw-r--r--lib/fuzzer/FuzzerIOPosix.cpp140
-rw-r--r--lib/fuzzer/FuzzerIOWindows.cpp323
-rw-r--r--lib/fuzzer/FuzzerInterface.h67
-rw-r--r--lib/fuzzer/FuzzerInternal.h155
-rw-r--r--lib/fuzzer/FuzzerLoop.cpp839
-rw-r--r--lib/fuzzer/FuzzerMain.cpp21
-rw-r--r--lib/fuzzer/FuzzerMerge.cpp390
-rw-r--r--lib/fuzzer/FuzzerMerge.h80
-rw-r--r--lib/fuzzer/FuzzerMutate.cpp533
-rw-r--r--lib/fuzzer/FuzzerMutate.h150
-rw-r--r--lib/fuzzer/FuzzerOptions.h75
-rw-r--r--lib/fuzzer/FuzzerRandom.h34
-rw-r--r--lib/fuzzer/FuzzerSHA1.cpp222
-rw-r--r--lib/fuzzer/FuzzerSHA1.h33
-rw-r--r--lib/fuzzer/FuzzerShmem.h69
-rw-r--r--lib/fuzzer/FuzzerShmemFuchsia.cpp38
-rw-r--r--lib/fuzzer/FuzzerShmemPosix.cpp103
-rw-r--r--lib/fuzzer/FuzzerShmemWindows.cpp64
-rw-r--r--lib/fuzzer/FuzzerTracePC.cpp602
-rw-r--r--lib/fuzzer/FuzzerTracePC.h296
-rw-r--r--lib/fuzzer/FuzzerUtil.cpp215
-rw-r--r--lib/fuzzer/FuzzerUtil.h87
-rw-r--r--lib/fuzzer/FuzzerUtilDarwin.cpp162
-rw-r--r--lib/fuzzer/FuzzerUtilFuchsia.cpp228
-rw-r--r--lib/fuzzer/FuzzerUtilLinux.cpp26
-rw-r--r--lib/fuzzer/FuzzerUtilPosix.cpp151
-rw-r--r--lib/fuzzer/FuzzerUtilWindows.cpp194
-rw-r--r--lib/fuzzer/FuzzerValueBitMap.h73
-rw-r--r--lib/fuzzer/README.txt1
-rw-r--r--lib/fuzzer/afl/afl_driver.cpp347
-rwxr-xr-xlib/fuzzer/build.sh11
-rwxr-xr-xlib/fuzzer/scripts/unbalanced_allocs.py93
-rw-r--r--lib/fuzzer/standalone/StandaloneFuzzTargetMain.c41
-rw-r--r--lib/fuzzer/tests/CMakeLists.txt46
-rw-r--r--lib/fuzzer/tests/FuzzerUnittest.cpp932
-rw-r--r--lib/hwasan/.clang-format1
-rw-r--r--lib/hwasan/CMakeLists.txt145
-rw-r--r--lib/hwasan/hwasan.cc303
-rw-r--r--lib/hwasan/hwasan.h172
-rw-r--r--lib/hwasan/hwasan.syms.extra2
-rw-r--r--lib/hwasan/hwasan_allocator.cc330
-rw-r--r--lib/hwasan/hwasan_allocator.h55
-rw-r--r--lib/hwasan/hwasan_blacklist.txt7
-rw-r--r--lib/hwasan/hwasan_flags.h30
-rw-r--r--lib/hwasan/hwasan_flags.inc29
-rw-r--r--lib/hwasan/hwasan_interceptors.cc483
-rw-r--r--lib/hwasan/hwasan_interface_internal.h97
-rw-r--r--lib/hwasan/hwasan_linux.cc251
-rw-r--r--lib/hwasan/hwasan_new_delete.cc66
-rw-r--r--lib/hwasan/hwasan_poisoning.cc36
-rw-r--r--lib/hwasan/hwasan_poisoning.h25
-rw-r--r--lib/hwasan/hwasan_report.cc133
-rw-r--r--lib/hwasan/hwasan_thread.cc75
-rw-r--r--lib/hwasan/hwasan_thread.h81
-rw-r--r--lib/interception/interception.h62
-rw-r--r--lib/interception/interception_linux.cc29
-rw-r--r--lib/interception/interception_linux.h11
-rw-r--r--lib/interception/interception_mac.cc5
-rw-r--r--lib/interception/interception_mac.h4
-rw-r--r--lib/interception/interception_type_test.cc9
-rw-r--r--lib/interception/interception_win.cc19
-rw-r--r--lib/interception/interception_win.h4
-rw-r--r--lib/interception/tests/CMakeLists.txt50
-rw-r--r--lib/lsan/CMakeLists.txt5
-rw-r--r--lib/lsan/lsan.cc15
-rw-r--r--lib/lsan/lsan.h40
-rw-r--r--lib/lsan/lsan_allocator.h11
-rw-r--r--lib/lsan/lsan_common.cc26
-rw-r--r--lib/lsan/lsan_common.h11
-rw-r--r--lib/lsan/lsan_common_linux.cc20
-rw-r--r--lib/lsan/lsan_common_mac.cc21
-rw-r--r--lib/lsan/lsan_interceptors.cc74
-rw-r--r--lib/lsan/weak_symbols.txt1
-rw-r--r--lib/msan/msan.cc17
-rw-r--r--lib/msan/msan.h66
-rw-r--r--lib/msan/msan_allocator.cc9
-rw-r--r--lib/msan/msan_interceptors.cc336
-rw-r--r--lib/msan/msan_linux.cc8
-rw-r--r--lib/msan/msan_report.cc31
-rw-r--r--lib/msan/tests/CMakeLists.txt37
-rw-r--r--lib/msan/tests/msan_test.cc24
-rw-r--r--lib/profile/CMakeLists.txt14
-rw-r--r--lib/profile/GCDAProfiling.c19
-rw-r--r--lib/profile/InstrProfData.inc4
-rw-r--r--lib/profile/InstrProfiling.c6
-rw-r--r--lib/profile/InstrProfilingFile.c16
-rw-r--r--lib/profile/InstrProfilingInternal.h3
-rw-r--r--lib/profile/InstrProfilingPlatformLinux.c6
-rw-r--r--lib/profile/InstrProfilingPlatformOther.c7
-rw-r--r--lib/profile/InstrProfilingPort.h14
-rw-r--r--lib/profile/InstrProfilingUtil.c68
-rw-r--r--lib/profile/InstrProfilingUtil.h3
-rw-r--r--lib/profile/InstrProfilingValue.c10
-rw-r--r--lib/profile/InstrProfilingWriter.c5
-rw-r--r--lib/profile/WindowsMMap.c61
-rw-r--r--lib/safestack/safestack.cc2
-rw-r--r--lib/sanitizer_common/CMakeLists.txt25
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.cc9
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.h13
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_checks.cc23
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_checks.h15
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_combined.h4
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_interface.h3
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_local_cache.h96
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_primary32.h73
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_primary64.h535
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_size_class_map.h30
-rw-r--r--lib/sanitizer_common/sanitizer_asm.h8
-rw-r--r--lib/sanitizer_common/sanitizer_bitvector.h4
-rw-r--r--lib/sanitizer_common/sanitizer_bvgraph.h2
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc147
-rw-r--r--lib/sanitizer_common/sanitizer_common.h219
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc198
-rwxr-xr-xlib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc2
-rw-r--r--lib/sanitizer_common/sanitizer_common_interface.inc1
-rw-r--r--lib/sanitizer_common/sanitizer_common_libcdep.cc180
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_fuchsia.cc240
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_interface.inc7
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc32
-rw-r--r--lib/sanitizer_common/sanitizer_errno.h4
-rw-r--r--lib/sanitizer_common/sanitizer_file.cc177
-rw-r--r--lib/sanitizer_common/sanitizer_file.h110
-rw-r--r--lib/sanitizer_common/sanitizer_flag_parser.h2
-rw-r--r--lib/sanitizer_common/sanitizer_flags.inc18
-rw-r--r--lib/sanitizer_common/sanitizer_fuchsia.cc539
-rw-r--r--lib/sanitizer_common/sanitizer_fuchsia.h31
-rw-r--r--lib/sanitizer_common/sanitizer_getauxval.h47
-rw-r--r--lib/sanitizer_common/sanitizer_interface_internal.h13
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h33
-rw-r--r--lib/sanitizer_common/sanitizer_libignore.cc5
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc354
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h24
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc295
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc38
-rw-r--r--lib/sanitizer_common/sanitizer_mac.h11
-rw-r--r--lib/sanitizer_common/sanitizer_mac_libcdep.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_mutex.h4
-rw-r--r--lib/sanitizer_common/sanitizer_platform.h33
-rw-r--r--lib/sanitizer_common/sanitizer_platform_interceptors.h372
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc363
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_netbsd.h582
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc8
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h45
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_solaris.cc366
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_solaris.h485
-rw-r--r--lib/sanitizer_common/sanitizer_posix.cc25
-rw-r--r--lib/sanitizer_common/sanitizer_posix.h2
-rw-r--r--lib/sanitizer_common/sanitizer_posix_libcdep.cc95
-rw-r--r--lib/sanitizer_common/sanitizer_printf.cc35
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps.h74
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_common.cc76
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_freebsd.cc42
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_linux.cc68
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_mac.cc163
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_solaris.cc57
-rw-r--r--lib/sanitizer_common/sanitizer_quarantine.h33
-rw-r--r--lib/sanitizer_common/sanitizer_report_decorator.h5
-rw-r--r--lib/sanitizer_common/sanitizer_signal_interceptors.inc87
-rw-r--r--lib/sanitizer_common/sanitizer_solaris.cc219
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.h9
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_printer.cc88
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc17
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_mac.cc10
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.cc3
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.cc4
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.h4
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc107
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_internal.h1
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc3
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc72
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc14
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_generic.inc35
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc3
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_arm.inc141
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc3
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.cc69
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.h5
-rw-r--r--lib/sanitizer_common/sanitizer_tls_get_addr.cc18
-rw-r--r--lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc11
-rw-r--r--lib/sanitizer_common/sanitizer_vector.h (renamed from lib/tsan/rtl/tsan_vector.h)32
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc180
-rw-r--r--lib/sanitizer_common/sanitizer_win_weak_interception.cc2
-rwxr-xr-xlib/sanitizer_common/scripts/check_lint.sh6
-rwxr-xr-xlib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh4
-rw-r--r--lib/sanitizer_common/tests/CMakeLists.txt64
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_test.cc294
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc86
-rw-r--r--lib/sanitizer_common/tests/sanitizer_libc_test.cc1
-rw-r--r--lib/sanitizer_common/tests/sanitizer_linux_test.cc1
-rw-r--r--lib/sanitizer_common/tests/sanitizer_test_utils.h6
-rw-r--r--lib/sanitizer_common/tests/sanitizer_vector_test.cc (renamed from lib/tsan/tests/unit/tsan_vector_test.cc)15
-rw-r--r--lib/scudo/CMakeLists.txt56
-rw-r--r--lib/scudo/scudo_allocator.cpp624
-rw-r--r--lib/scudo/scudo_allocator.h51
-rw-r--r--lib/scudo/scudo_allocator_combined.h14
-rw-r--r--lib/scudo/scudo_allocator_secondary.h76
-rw-r--r--lib/scudo/scudo_crc32.h2
-rw-r--r--lib/scudo/scudo_flags.cpp59
-rw-r--r--lib/scudo/scudo_flags.inc22
-rw-r--r--lib/scudo/scudo_interface_internal.h22
-rw-r--r--lib/scudo/scudo_new_delete.cpp2
-rw-r--r--lib/scudo/scudo_platform.h80
-rw-r--r--lib/scudo/scudo_tls.h47
-rw-r--r--lib/scudo/scudo_tls_android.cpp95
-rw-r--r--lib/scudo/scudo_tls_android.inc44
-rw-r--r--lib/scudo/scudo_tls_context_android.inc54
-rw-r--r--lib/scudo/scudo_tls_context_linux.inc29
-rw-r--r--lib/scudo/scudo_tls_linux.inc48
-rw-r--r--lib/scudo/scudo_tsd.h72
-rw-r--r--lib/scudo/scudo_tsd_exclusive.cpp (renamed from lib/scudo/scudo_tls_linux.cpp)30
-rw-r--r--lib/scudo/scudo_tsd_exclusive.inc46
-rw-r--r--lib/scudo/scudo_tsd_shared.cpp87
-rw-r--r--lib/scudo/scudo_tsd_shared.inc48
-rw-r--r--lib/scudo/scudo_utils.cpp138
-rw-r--r--lib/scudo/scudo_utils.h64
-rw-r--r--lib/stats/CMakeLists.txt5
-rw-r--r--lib/stats/stats.cc1
-rw-r--r--lib/tsan/CMakeLists.txt50
-rwxr-xr-xlib/tsan/check_analyze.sh10
-rw-r--r--lib/tsan/dd/CMakeLists.txt4
-rwxr-xr-xlib/tsan/go/buildgo.sh18
-rw-r--r--lib/tsan/rtl/tsan_fd.cc6
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc558
-rw-r--r--lib/tsan/rtl/tsan_interceptors.h12
-rw-r--r--lib/tsan/rtl/tsan_interceptors_mac.cc20
-rw-r--r--lib/tsan/rtl/tsan_interface_ann.cc6
-rw-r--r--lib/tsan/rtl/tsan_libdispatch_mac.cc15
-rw-r--r--lib/tsan/rtl/tsan_malloc_mac.cc4
-rw-r--r--lib/tsan/rtl/tsan_mman.cc91
-rw-r--r--lib/tsan/rtl/tsan_mman.h15
-rw-r--r--lib/tsan/rtl/tsan_platform.h144
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc9
-rw-r--r--lib/tsan/rtl/tsan_platform_mac.cc6
-rw-r--r--lib/tsan/rtl/tsan_report.cc44
-rw-r--r--lib/tsan/rtl/tsan_report.h2
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc50
-rw-r--r--lib/tsan/rtl/tsan_rtl.h30
-rw-r--r--lib/tsan/rtl/tsan_rtl_aarch64.S50
-rw-r--r--lib/tsan/rtl/tsan_rtl_amd64.S104
-rw-r--r--lib/tsan/rtl/tsan_rtl_mutex.cc4
-rw-r--r--lib/tsan/rtl/tsan_rtl_report.cc71
-rw-r--r--lib/tsan/rtl/tsan_rtl_thread.cc2
-rw-r--r--lib/tsan/rtl/tsan_sync.h4
-rw-r--r--lib/tsan/rtl/tsan_trace.h2
-rw-r--r--lib/tsan/tests/CMakeLists.txt104
-rw-r--r--lib/tsan/tests/rtl/tsan_test_util_posix.cc4
-rw-r--r--lib/tsan/tests/unit/CMakeLists.txt3
-rw-r--r--lib/tsan/tests/unit/tsan_mman_test.cc89
-rw-r--r--lib/ubsan/CMakeLists.txt57
-rw-r--r--lib/ubsan/ubsan_checks.inc1
-rw-r--r--lib/ubsan/ubsan_diag.cc37
-rw-r--r--lib/ubsan/ubsan_diag.h11
-rw-r--r--lib/ubsan/ubsan_diag_standalone.cc5
-rw-r--r--lib/ubsan/ubsan_flags.cc6
-rw-r--r--lib/ubsan/ubsan_handlers.cc52
-rw-r--r--lib/ubsan/ubsan_handlers.h22
-rw-r--r--lib/ubsan/ubsan_handlers_cxx.cc4
-rw-r--r--lib/ubsan/ubsan_init.cc38
-rw-r--r--lib/ubsan/ubsan_init_standalone.cc13
-rw-r--r--lib/ubsan/ubsan_interface.inc5
-rw-r--r--lib/ubsan/ubsan_platform.h11
-rw-r--r--lib/ubsan/ubsan_signals_standalone.cc53
-rw-r--r--lib/ubsan/ubsan_signals_standalone.h25
-rw-r--r--lib/ubsan_minimal/CMakeLists.txt55
-rw-r--r--lib/ubsan_minimal/ubsan.syms.extra1
-rw-r--r--lib/ubsan_minimal/ubsan_minimal_handlers.cc104
-rw-r--r--lib/xray/CMakeLists.txt71
-rw-r--r--lib/xray/tests/CMakeLists.txt46
-rw-r--r--lib/xray/tests/unit/buffer_queue_test.cc4
-rw-r--r--lib/xray/tests/unit/fdr_logging_test.cc107
-rw-r--r--lib/xray/weak_symbols.txt4
-rw-r--r--lib/xray/xray_buffer_queue.cc79
-rw-r--r--lib/xray/xray_buffer_queue.h97
-rw-r--r--lib/xray/xray_fdr_log_records.h3
-rw-r--r--lib/xray/xray_fdr_logging.cc206
-rw-r--r--lib/xray/xray_fdr_logging.h1
-rw-r--r--lib/xray/xray_fdr_logging_impl.h605
-rw-r--r--lib/xray/xray_flags.h1
-rw-r--r--lib/xray/xray_flags.inc28
-rw-r--r--lib/xray/xray_init.cc35
-rw-r--r--lib/xray/xray_inmemory_log.cc453
-rw-r--r--lib/xray/xray_inmemory_log.h44
-rw-r--r--lib/xray/xray_interface.cc314
-rw-r--r--lib/xray/xray_interface_internal.h6
-rw-r--r--lib/xray/xray_log_interface.cc63
-rw-r--r--lib/xray/xray_trampoline_x86_64.S147
-rw-r--r--lib/xray/xray_utils.cc3
-rw-r--r--lib/xray/xray_x86_64.cc40
428 files changed, 25096 insertions, 5281 deletions
diff --git a/lib/BlocksRuntime/Block.h b/lib/BlocksRuntime/Block.h
index 55cdd01a9123..e6cb142fd755 100644
--- a/lib/BlocksRuntime/Block.h
+++ b/lib/BlocksRuntime/Block.h
@@ -27,7 +27,7 @@
#if !defined(BLOCK_EXPORT)
# if defined(__cplusplus)
-# define BLOCK_EXPORT extern "C"
+# define BLOCK_EXPORT extern "C"
# else
# define BLOCK_EXPORT extern
# endif
diff --git a/lib/BlocksRuntime/Block_private.h b/lib/BlocksRuntime/Block_private.h
index 8ae821815ebe..91d8d8a9850b 100644
--- a/lib/BlocksRuntime/Block_private.h
+++ b/lib/BlocksRuntime/Block_private.h
@@ -27,7 +27,7 @@
#if !defined(BLOCK_EXPORT)
# if defined(__cplusplus)
-# define BLOCK_EXPORT extern "C"
+# define BLOCK_EXPORT extern "C"
# else
# define BLOCK_EXPORT extern
# endif
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 90f72d02afa1..b3731f653a01 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -39,10 +39,16 @@ if(COMPILER_RT_BUILD_SANITIZERS)
foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD})
compiler_rt_build_runtime(${sanitizer})
endforeach()
+endif()
+if(COMPILER_RT_BUILD_PROFILE AND COMPILER_RT_HAS_PROFILE)
compiler_rt_build_runtime(profile)
endif()
if(COMPILER_RT_BUILD_XRAY)
compiler_rt_build_runtime(xray)
endif()
+
+if(COMPILER_RT_BUILD_LIBFUZZER)
+ compiler_rt_build_runtime(fuzzer)
+endif()
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index a2d4630dfc33..da82e485b581 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -8,9 +8,11 @@ set(ASAN_SOURCES
asan_errors.cc
asan_fake_stack.cc
asan_flags.cc
+ asan_fuchsia.cc
asan_globals.cc
asan_globals_win.cc
asan_interceptors.cc
+ asan_interceptors_memintrinsics.cc
asan_linux.cc
asan_mac.cc
asan_malloc_linux.cc
@@ -19,8 +21,10 @@ set(ASAN_SOURCES
asan_memory_profile.cc
asan_poisoning.cc
asan_posix.cc
+ asan_premap_shadow.cc
asan_report.cc
asan_rtl.cc
+ asan_shadow_setup.cc
asan_stack.cc
asan_stats.cc
asan_suppressions.cc
@@ -36,10 +40,11 @@ set(ASAN_PREINIT_SOURCES
include_directories(..)
set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+set(ASAN_COMMON_DEFINITIONS ${COMPILER_RT_ASAN_SHADOW_SCALE_DEFINITION})
append_rtti_flag(OFF ASAN_CFLAGS)
-set(ASAN_DYNAMIC_LINK_FLAGS)
+set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
if(ANDROID)
# On Android, -z global does not do what it is documented to do.
@@ -64,12 +69,12 @@ append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
-ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS)
-append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
+set(ASAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY} ${SANITIZER_COMMON_LINK_LIBS})
+
append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
-append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS)
# Compile ASan sources into an object library.
@@ -164,15 +169,15 @@ else()
PARENT_TARGET asan)
foreach(arch ${ASAN_SUPPORTED_ARCH})
- if (UNIX AND NOT ${arch} MATCHES "i386|i686")
+ if (UNIX)
add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch}
LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch}
EXTRA asan.syms.extra)
set(VERSION_SCRIPT_FLAG
-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
- set_source_files_properties(
+ set_property(SOURCE
${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
- PROPERTIES
+ APPEND PROPERTY
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
else()
set(VERSION_SCRIPT_FLAG)
@@ -198,10 +203,11 @@ else()
ARCHS ${arch}
OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
RTAsan_dynamic
- # The only purpose of RTAsan_dynamic_version_script_dummy is to carry
- # a dependency of the shared runtime on the version script. With CMake
- # 3.1 or later it can be replaced with a straightforward
+ # The only purpose of RTAsan_dynamic_version_script_dummy is to
+ # carry a dependency of the shared runtime on the version script.
+ # Replacing it with a straightforward
# add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list)
+ # generates an order-only dependency in ninja.
RTAsan_dynamic_version_script_dummy
RTUbsan_cxx
${ASAN_DYNAMIC_WEAK_INTERCEPTION}
@@ -212,7 +218,7 @@ else()
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
PARENT_TARGET asan)
- if (UNIX AND NOT ${arch} MATCHES "i386|i686")
+ if (UNIX AND NOT ${arch} STREQUAL "i386")
add_sanitizer_rt_symbols(clang_rt.asan_cxx
ARCHS ${arch})
add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
diff --git a/lib/asan/asan_activation.cc b/lib/asan/asan_activation.cc
index 66eba9ce2748..d642be93488d 100644
--- a/lib/asan/asan_activation.cc
+++ b/lib/asan/asan_activation.cc
@@ -16,8 +16,10 @@
#include "asan_allocator.h"
#include "asan_flags.h"
#include "asan_internal.h"
+#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
namespace __asan {
@@ -110,8 +112,9 @@ void AsanDeactivate() {
AllocatorOptions disabled = asan_deactivated_flags.allocator_options;
disabled.quarantine_size_mb = 0;
disabled.thread_local_quarantine_size_kb = 0;
- disabled.min_redzone = 16; // Redzone must be at least 16 bytes long.
- disabled.max_redzone = 16;
+ // Redzone must be at least Max(16, granularity) bytes long.
+ disabled.min_redzone = Max(16, (int)SHADOW_GRANULARITY);
+ disabled.max_redzone = disabled.min_redzone;
disabled.alloc_dealloc_mismatch = false;
disabled.may_return_null = true;
ReInitializeAllocator(disabled);
diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
index 92963ddfc4da..a437ae1cd3b1 100644
--- a/lib/asan/asan_allocator.cc
+++ b/lib/asan/asan_allocator.cc
@@ -84,7 +84,10 @@ struct ChunkHeader {
// This field is used for small sizes. For large sizes it is equal to
// SizeClassMap::kMaxSize and the actual size is stored in the
// SecondaryAllocator's metadata.
- u32 user_requested_size;
+ u32 user_requested_size : 29;
+ // align < 8 -> 0
+ // else -> log2(min(align, 512)) - 2
+ u32 user_requested_alignment_log : 3;
u32 alloc_context_id;
};
@@ -271,9 +274,9 @@ struct Allocator {
atomic_store(&max_redzone, options.max_redzone, memory_order_release);
}
- void Initialize(const AllocatorOptions &options) {
+ void InitLinkerInitialized(const AllocatorOptions &options) {
SetAllocatorMayReturnNull(options.may_return_null);
- allocator.Init(options.release_to_os_interval_ms);
+ allocator.InitLinkerInitialized(options.release_to_os_interval_ms);
SharedInitCode(options);
}
@@ -351,6 +354,20 @@ struct Allocator {
return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz));
}
+ static uptr ComputeUserRequestedAlignmentLog(uptr user_requested_alignment) {
+ if (user_requested_alignment < 8)
+ return 0;
+ if (user_requested_alignment > 512)
+ user_requested_alignment = 512;
+ return Log2(user_requested_alignment) - 2;
+ }
+
+ static uptr ComputeUserAlignment(uptr user_requested_alignment_log) {
+ if (user_requested_alignment_log == 0)
+ return 0;
+ return 1LL << (user_requested_alignment_log + 2);
+ }
+
// We have an address between two chunks, and we want to report just one.
AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk,
AsanChunk *right_chunk) {
@@ -385,6 +402,8 @@ struct Allocator {
Flags &fl = *flags();
CHECK(stack);
const uptr min_alignment = SHADOW_GRANULARITY;
+ const uptr user_requested_alignment_log =
+ ComputeUserRequestedAlignmentLog(alignment);
if (alignment < min_alignment)
alignment = min_alignment;
if (size == 0) {
@@ -472,6 +491,7 @@ struct Allocator {
meta[0] = size;
meta[1] = chunk_beg;
}
+ m->user_requested_alignment_log = user_requested_alignment_log;
m->alloc_context_id = StackDepotPut(*stack);
@@ -573,8 +593,8 @@ struct Allocator {
}
}
- void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
- AllocType alloc_type) {
+ void Deallocate(void *ptr, uptr delete_size, uptr delete_alignment,
+ BufferedStackTrace *stack, AllocType alloc_type) {
uptr p = reinterpret_cast<uptr>(ptr);
if (p == 0) return;
@@ -601,11 +621,14 @@ struct Allocator {
ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
(AllocType)alloc_type);
}
- }
-
- if (delete_size && flags()->new_delete_type_mismatch &&
- delete_size != m->UsedSize()) {
- ReportNewDeleteSizeMismatch(p, delete_size, stack);
+ } else {
+ if (flags()->new_delete_type_mismatch &&
+ (alloc_type == FROM_NEW || alloc_type == FROM_NEW_BR) &&
+ ((delete_size && delete_size != m->UsedSize()) ||
+ ComputeUserRequestedAlignmentLog(delete_alignment) !=
+ m->user_requested_alignment_log)) {
+ ReportNewDeleteTypeMismatch(p, delete_size, delete_alignment, stack);
+ }
}
QuarantineChunk(m, ptr, stack);
@@ -631,7 +654,7 @@ struct Allocator {
// If realloc() races with free(), we may start copying freed memory.
// However, we will report racy double-free later anyway.
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
- Deallocate(old_ptr, 0, stack, FROM_MALLOC);
+ Deallocate(old_ptr, 0, 0, stack, FROM_MALLOC);
}
return new_ptr;
}
@@ -716,6 +739,22 @@ struct Allocator {
return AsanChunkView(m1);
}
+ void Purge() {
+ AsanThread *t = GetCurrentThread();
+ if (t) {
+ AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
+ quarantine.DrainAndRecycle(GetQuarantineCache(ms),
+ QuarantineCallback(GetAllocatorCache(ms)));
+ }
+ {
+ SpinMutexLock l(&fallback_mutex);
+ quarantine.DrainAndRecycle(&fallback_quarantine_cache,
+ QuarantineCallback(&fallback_allocator_cache));
+ }
+
+ allocator.ForceReleaseToOS();
+ }
+
void PrintStats() {
allocator.PrintStats();
quarantine.PrintStats();
@@ -750,6 +789,9 @@ bool AsanChunkView::IsQuarantined() const {
uptr AsanChunkView::Beg() const { return chunk_->Beg(); }
uptr AsanChunkView::End() const { return Beg() + UsedSize(); }
uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); }
+u32 AsanChunkView::UserRequestedAlignment() const {
+ return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log);
+}
uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; }
uptr AsanChunkView::FreeTid() const { return chunk_->free_tid; }
AllocType AsanChunkView::GetAllocType() const {
@@ -775,7 +817,7 @@ StackTrace AsanChunkView::GetFreeStack() const {
}
void InitializeAllocator(const AllocatorOptions &options) {
- instance.Initialize(options);
+ instance.InitLinkerInitialized(options);
}
void ReInitializeAllocator(const AllocatorOptions &options) {
@@ -802,12 +844,12 @@ void PrintInternalAllocatorStats() {
}
void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
- instance.Deallocate(ptr, 0, stack, alloc_type);
+ instance.Deallocate(ptr, 0, 0, stack, alloc_type);
}
-void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
- AllocType alloc_type) {
- instance.Deallocate(ptr, size, stack, alloc_type);
+void asan_delete(void *ptr, uptr size, uptr alignment,
+ BufferedStackTrace *stack, AllocType alloc_type) {
+ instance.Deallocate(ptr, size, alignment, stack, alloc_type);
}
void *asan_malloc(uptr size, BufferedStackTrace *stack) {
@@ -823,7 +865,7 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true));
if (size == 0) {
if (flags()->allocator_frees_and_returns_null_on_realloc_zero) {
- instance.Deallocate(p, 0, stack, FROM_MALLOC);
+ instance.Deallocate(p, 0, 0, stack, FROM_MALLOC);
return nullptr;
}
// Allocate a size of 1 if we shouldn't free() on Realloc to 0
@@ -839,6 +881,10 @@ void *asan_valloc(uptr size, BufferedStackTrace *stack) {
void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
uptr PageSize = GetPageSizeCached();
+ if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
+ errno = errno_ENOMEM;
+ return AsanAllocator::FailureHandler::OnBadRequest();
+ }
// pvalloc(0) should allocate one page.
size = size ? RoundUpTo(size, PageSize) : PageSize;
return SetErrnoOnNull(
@@ -1007,6 +1053,10 @@ uptr __sanitizer_get_allocated_size(const void *p) {
return allocated_size;
}
+void __sanitizer_purge_allocator() {
+ instance.Purge();
+}
+
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default (no-op) implementation of malloc hooks.
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook,
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index ad1aeb58a86b..26483db4c60e 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -58,6 +58,7 @@ class AsanChunkView {
uptr Beg() const; // First byte of user memory.
uptr End() const; // Last byte of user memory.
uptr UsedSize() const; // Size requested by the user.
+ u32 UserRequestedAlignment() const; // Originally requested alignment.
uptr AllocTid() const;
uptr FreeTid() const;
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
@@ -119,7 +120,11 @@ struct AsanMapUnmapCallback {
};
#if SANITIZER_CAN_USE_ALLOCATOR64
-# if defined(__powerpc64__)
+# if SANITIZER_FUCHSIA
+const uptr kAllocatorSpace = ~(uptr)0;
+const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+typedef DefaultSizeClassMap SizeClassMap;
+# elif defined(__powerpc64__)
const uptr kAllocatorSpace = 0xa0000000000ULL;
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
typedef DefaultSizeClassMap SizeClassMap;
@@ -193,8 +198,8 @@ struct AsanThreadLocalMallocStorage {
void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
AllocType alloc_type);
void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
-void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
- AllocType alloc_type);
+void asan_delete(void *ptr, uptr size, uptr alignment,
+ BufferedStackTrace *stack, AllocType alloc_type);
void *asan_malloc(uptr size, BufferedStackTrace *stack);
void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
diff --git a/lib/asan/asan_descriptions.cc b/lib/asan/asan_descriptions.cc
index 822a6a62d64e..86c6af7d9f75 100644
--- a/lib/asan/asan_descriptions.cc
+++ b/lib/asan/asan_descriptions.cc
@@ -122,6 +122,7 @@ static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
}
descr->chunk_begin = chunk.Beg();
descr->chunk_size = chunk.UsedSize();
+ descr->user_requested_alignment = chunk.UserRequestedAlignment();
descr->alloc_type = chunk.GetAllocType();
}
@@ -150,7 +151,7 @@ static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size,
(void *)descr.chunk_begin,
(void *)(descr.chunk_begin + descr.chunk_size));
- str.append("%s", d.EndLocation());
+ str.append("%s", d.Default());
Printf("%s", str.data());
}
@@ -260,7 +261,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
// FIXME: we may want to also print the size of the access here,
// but in case of accesses generated by memset it may be confusing.
str.append("%s <== Memory access at offset %zd %s this variable%s\n",
- d.Location(), addr, pos_descr, d.EndLocation());
+ d.Location(), addr, pos_descr, d.Default());
} else {
str.append("\n");
}
@@ -295,7 +296,7 @@ static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
MaybeDemangleGlobalName(g.name));
PrintGlobalLocation(&str, g);
str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
- str.append("%s", d.EndLocation());
+ str.append("%s", d.Default());
PrintGlobalNameIfASCII(&str, g);
Printf("%s", str.data());
}
@@ -335,6 +336,26 @@ void GlobalAddressDescription::Print(const char *bug_type) const {
}
}
+bool GlobalAddressDescription::PointsInsideTheSameVariable(
+ const GlobalAddressDescription &other) const {
+ if (size == 0 || other.size == 0) return false;
+
+ for (uptr i = 0; i < size; i++) {
+ const __asan_global &a = globals[i];
+ for (uptr j = 0; j < other.size; j++) {
+ const __asan_global &b = other.globals[j];
+ if (a.beg == b.beg &&
+ a.beg <= addr &&
+ b.beg <= other.addr &&
+ (addr + access_size) < (a.beg + a.size) &&
+ (other.addr + other.access_size) < (b.beg + b.size))
+ return true;
+ }
+ }
+
+ return false;
+}
+
void StackAddressDescription::Print() const {
Decorator d;
char tname[128];
@@ -343,10 +364,10 @@ void StackAddressDescription::Print() const {
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
if (!frame_descr) {
- Printf("%s\n", d.EndLocation());
+ Printf("%s\n", d.Default());
return;
}
- Printf(" at offset %zu in frame%s\n", offset, d.EndLocation());
+ Printf(" at offset %zu in frame%s\n", offset, d.Default());
// Now we print the frame where the alloca has happened.
// We print this frame as a stack trace with one element.
@@ -355,7 +376,7 @@ void StackAddressDescription::Print() const {
// previously. That's unfortunate, but I have no better solution,
// especially given that the alloca may be from entirely different place
// (e.g. use-after-scope, or different thread's stack).
- Printf("%s", d.EndLocation());
+ Printf("%s", d.Default());
StackTrace alloca_stack(&frame_pc, 1);
alloca_stack.Print();
@@ -405,18 +426,18 @@ void HeapAddressDescription::Print() const {
Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
free_thread->tid,
ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
- d.EndAllocation());
+ d.Default());
StackTrace free_stack = GetStackTraceFromId(free_stack_id);
free_stack.Print();
Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(),
alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
- d.EndAllocation());
+ d.Default());
} else {
Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
- d.EndAllocation());
+ d.Default());
}
alloc_stack.Print();
DescribeThread(GetCurrentThread());
diff --git a/lib/asan/asan_descriptions.h b/lib/asan/asan_descriptions.h
index 0ee677eb7d0e..1a1b01cf20cd 100644
--- a/lib/asan/asan_descriptions.h
+++ b/lib/asan/asan_descriptions.h
@@ -34,11 +34,8 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
public:
Decorator() : SanitizerCommonDecorator() {}
const char *Access() { return Blue(); }
- const char *EndAccess() { return Default(); }
const char *Location() { return Green(); }
- const char *EndLocation() { return Default(); }
const char *Allocation() { return Magenta(); }
- const char *EndAllocation() { return Default(); }
const char *ShadowByte(u8 byte) {
switch (byte) {
@@ -72,9 +69,6 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
return Default();
}
}
- const char *EndShadowByte() { return Default(); }
- const char *MemoryByte() { return Magenta(); }
- const char *EndMemoryByte() { return Default(); }
};
enum ShadowKind : u8 {
@@ -108,6 +102,7 @@ struct ChunkAccess {
sptr offset;
uptr chunk_begin;
uptr chunk_size;
+ u32 user_requested_alignment : 12;
u32 access_type : 2;
u32 alloc_type : 2;
};
@@ -151,6 +146,10 @@ struct GlobalAddressDescription {
u8 size;
void Print(const char *bug_type = "") const;
+
+ // Returns true when this descriptions points inside the same global variable
+ // as other. Descriptions can have different address within the variable
+ bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
};
bool GetGlobalAddressInformation(uptr addr, uptr access_size,
diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc
index b7a38eb7cece..0f4a3abff9a7 100644
--- a/lib/asan/asan_errors.cc
+++ b/lib/asan/asan_errors.cc
@@ -13,7 +13,6 @@
//===----------------------------------------------------------------------===//
#include "asan_errors.h"
-#include <signal.h>
#include "asan_descriptions.h"
#include "asan_mapping.h"
#include "asan_report.h"
@@ -22,82 +21,26 @@
namespace __asan {
-void ErrorStackOverflow::Print() {
- Decorator d;
- Printf("%s", d.Warning());
- Report(
- "ERROR: AddressSanitizer: %s on address %p"
- " (pc %p bp %p sp %p T%d)\n", scariness.GetDescription(),
- (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid);
- Printf("%s", d.EndWarning());
- scariness.Print();
- BufferedStackTrace stack;
- GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
- common_flags()->fast_unwind_on_fatal);
- stack.Print();
- ReportErrorSummary(scariness.GetDescription(), &stack);
-}
-
-static void MaybeDumpInstructionBytes(uptr pc) {
- if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) return;
- InternalScopedString str(1024);
- str.append("First 16 instruction bytes at pc: ");
- if (IsAccessibleMemoryRange(pc, 16)) {
- for (int i = 0; i < 16; ++i) {
- PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/ false, " ");
- }
- str.append("\n");
- } else {
- str.append("unaccessible\n");
- }
- Report("%s", str.data());
-}
-
-static void MaybeDumpRegisters(void *context) {
- if (!flags()->dump_registers) return;
- SignalContext::DumpAllRegisters(context);
-}
-
-static void MaybeReportNonExecRegion(uptr pc) {
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
- MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
- MemoryMappedSegment segment;
- while (proc_maps.Next(&segment)) {
- if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
- Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
- }
+static void OnStackUnwind(const SignalContext &sig,
+ const void *callback_context,
+ BufferedStackTrace *stack) {
+ bool fast = common_flags()->fast_unwind_on_fatal;
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
+ // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
+ // yields the call stack of the signal's handler and not of the code
+ // that raised the signal (as it does on Linux).
+ fast = true;
#endif
+ // Tests and maybe some users expect that scariness is going to be printed
+ // just before the stack. As only asan has scariness score we have no
+ // corresponding code in the sanitizer_common and we use this callback to
+ // print it.
+ static_cast<const ScarinessScoreBase *>(callback_context)->Print();
+ GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context, fast);
}
void ErrorDeadlySignal::Print() {
- Decorator d;
- Printf("%s", d.Warning());
- const char *description = __sanitizer::DescribeSignalOrException(signo);
- Report(
- "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p "
- "T%d)\n",
- description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid);
- Printf("%s", d.EndWarning());
- if (pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n");
- if (is_memory_access) {
- const char *access_type =
- write_flag == SignalContext::WRITE
- ? "WRITE"
- : (write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
- Report("The signal is caused by a %s memory access.\n", access_type);
- if (addr < GetPageSizeCached())
- Report("Hint: address points to the zero page.\n");
- }
- MaybeReportNonExecRegion(pc);
- scariness.Print();
- BufferedStackTrace stack;
- GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
- common_flags()->fast_unwind_on_fatal);
- stack.Print();
- MaybeDumpInstructionBytes(pc);
- MaybeDumpRegisters(context);
- Printf("AddressSanitizer can not provide additional info.\n");
- ReportErrorSummary(description, &stack);
+ ReportDeadlySignal(signal, tid, &OnStackUnwind, &scariness);
}
void ErrorDoubleFree::Print() {
@@ -109,7 +52,7 @@ void ErrorDoubleFree::Print() {
"thread T%d%s:\n",
scariness.GetDescription(), addr_description.addr, tid,
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
scariness.Print();
GET_STACK_TRACE_FATAL(second_free_stack->trace[0],
second_free_stack->top_frame_bp);
@@ -118,7 +61,7 @@ void ErrorDoubleFree::Print() {
ReportErrorSummary(scariness.GetDescription(), &stack);
}
-void ErrorNewDeleteSizeMismatch::Print() {
+void ErrorNewDeleteTypeMismatch::Print() {
Decorator d;
Printf("%s", d.Warning());
char tname[128];
@@ -127,11 +70,29 @@ void ErrorNewDeleteSizeMismatch::Print() {
"T%d%s:\n",
scariness.GetDescription(), addr_description.addr, tid,
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
- Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
- Printf(
- " size of the allocated type: %zd bytes;\n"
- " size of the deallocated type: %zd bytes.\n",
- addr_description.chunk_access.chunk_size, delete_size);
+ Printf("%s object passed to delete has wrong type:\n", d.Default());
+ if (delete_size != 0) {
+ Printf(
+ " size of the allocated type: %zd bytes;\n"
+ " size of the deallocated type: %zd bytes.\n",
+ addr_description.chunk_access.chunk_size, delete_size);
+ }
+ const uptr user_alignment =
+ addr_description.chunk_access.user_requested_alignment;
+ if (delete_alignment != user_alignment) {
+ char user_alignment_str[32];
+ char delete_alignment_str[32];
+ internal_snprintf(user_alignment_str, sizeof(user_alignment_str),
+ "%zd bytes", user_alignment);
+ internal_snprintf(delete_alignment_str, sizeof(delete_alignment_str),
+ "%zd bytes", delete_alignment);
+ static const char *kDefaultAlignment = "default-aligned";
+ Printf(
+ " alignment of the allocated type: %s;\n"
+ " alignment of the deallocated type: %s.\n",
+ user_alignment > 0 ? user_alignment_str : kDefaultAlignment,
+ delete_alignment > 0 ? delete_alignment_str : kDefaultAlignment);
+ }
CHECK_GT(free_stack->size, 0);
scariness.Print();
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
@@ -152,7 +113,7 @@ void ErrorFreeNotMalloced::Print() {
"which was not malloc()-ed: %p in thread T%d%s\n",
addr_description.Address(), tid,
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
CHECK_GT(free_stack->size, 0);
scariness.Print();
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
@@ -173,7 +134,7 @@ void ErrorAllocTypeMismatch::Print() {
scariness.GetDescription(),
alloc_names[alloc_type], dealloc_names[dealloc_type],
addr_description.addr);
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
CHECK_GT(dealloc_stack->size, 0);
scariness.Print();
GET_STACK_TRACE_FATAL(dealloc_stack->trace[0], dealloc_stack->top_frame_bp);
@@ -192,7 +153,7 @@ void ErrorMallocUsableSizeNotOwned::Print() {
"ERROR: AddressSanitizer: attempting to call malloc_usable_size() for "
"pointer which is not owned: %p\n",
addr_description.Address());
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
stack->Print();
addr_description.Print();
ReportErrorSummary(scariness.GetDescription(), stack);
@@ -205,7 +166,7 @@ void ErrorSanitizerGetAllocatedSizeNotOwned::Print() {
"ERROR: AddressSanitizer: attempting to call "
"__sanitizer_get_allocated_size() for pointer which is not owned: %p\n",
addr_description.Address());
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
stack->Print();
addr_description.Print();
ReportErrorSummary(scariness.GetDescription(), stack);
@@ -222,7 +183,7 @@ void ErrorStringFunctionMemoryRangesOverlap::Print() {
bug_type, addr1_description.Address(),
addr1_description.Address() + length1, addr2_description.Address(),
addr2_description.Address() + length2);
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
scariness.Print();
stack->Print();
addr1_description.Print();
@@ -235,7 +196,7 @@ void ErrorStringFunctionSizeOverflow::Print() {
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: %s: (size=%zd)\n",
scariness.GetDescription(), size);
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
scariness.Print();
stack->Print();
addr_description.Print();
@@ -263,7 +224,7 @@ void ErrorODRViolation::Print() {
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),
global1.beg);
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
InternalScopedString g1_loc(256), g2_loc(256);
PrintGlobalLocation(&g1_loc, global1);
PrintGlobalLocation(&g2_loc, global2);
@@ -292,7 +253,7 @@ void ErrorInvalidPointerPair::Print() {
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: %s: %p %p\n", scariness.GetDescription(),
addr1_description.Address(), addr2_description.Address());
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
GET_STACK_TRACE_FATAL(pc, bp);
stack.Print();
addr1_description.Print();
@@ -477,9 +438,14 @@ static void PrintShadowMemoryForAddress(uptr addr) {
InternalScopedString str(4096 * 8);
str.append("Shadow bytes around the buggy address:\n");
for (int i = -5; i <= 5; i++) {
+ uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row;
+ // Skip rows that would be outside the shadow range. This can happen when
+ // the user address is near the bottom, top, or shadow gap of the address
+ // space.
+ if (!AddrIsInShadow(row_shadow_addr)) continue;
const char *prefix = (i == 0) ? "=>" : " ";
- PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
- (u8 *)shadow_addr, n_bytes_per_row);
+ PrintShadowBytes(&str, prefix, (u8 *)row_shadow_addr, (u8 *)shadow_addr,
+ n_bytes_per_row);
}
if (flags()->print_legend) PrintLegend(&str);
Printf("%s", str.data());
@@ -491,13 +457,13 @@ void ErrorGeneric::Print() {
uptr addr = addr_description.Address();
Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n",
bug_descr, (void *)addr, pc, bp, sp);
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
char tname[128];
Printf("%s%s of size %zu at %p thread T%d%s%s\n", d.Access(),
access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size,
(void *)addr, tid,
- ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.EndAccess());
+ ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.Default());
scariness.Print();
GET_STACK_TRACE_FATAL(pc, bp);
diff --git a/lib/asan/asan_errors.h b/lib/asan/asan_errors.h
index 9a124924470e..518ba0c6945e 100644
--- a/lib/asan/asan_errors.h
+++ b/lib/asan/asan_errors.h
@@ -27,61 +27,28 @@ struct ErrorBase {
u32 tid;
};
-struct ErrorStackOverflow : ErrorBase {
- uptr addr, pc, bp, sp;
- // ErrorStackOverflow never owns the context.
- void *context;
- // VS2013 doesn't implement unrestricted unions, so we need a trivial default
- // constructor
- ErrorStackOverflow() = default;
- ErrorStackOverflow(u32 tid, const SignalContext &sig)
- : ErrorBase(tid),
- addr(sig.addr),
- pc(sig.pc),
- bp(sig.bp),
- sp(sig.sp),
- context(sig.context) {
- scariness.Clear();
- scariness.Scare(10, "stack-overflow");
- }
- void Print();
-};
-
struct ErrorDeadlySignal : ErrorBase {
- uptr addr, pc, bp, sp;
- // ErrorDeadlySignal never owns the context.
- void *context;
- int signo;
- SignalContext::WriteFlag write_flag;
- bool is_memory_access;
+ SignalContext signal;
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
// constructor
ErrorDeadlySignal() = default;
- ErrorDeadlySignal(u32 tid, const SignalContext &sig, int signo_)
- : ErrorBase(tid),
- addr(sig.addr),
- pc(sig.pc),
- bp(sig.bp),
- sp(sig.sp),
- context(sig.context),
- signo(signo_),
- write_flag(sig.write_flag),
- is_memory_access(sig.is_memory_access) {
+ ErrorDeadlySignal(u32 tid, const SignalContext &sig)
+ : ErrorBase(tid), signal(sig) {
scariness.Clear();
- if (is_memory_access) {
- if (addr < GetPageSizeCached()) {
- scariness.Scare(10, "null-deref");
- } else if (addr == pc) {
- scariness.Scare(60, "wild-jump");
- } else if (write_flag == SignalContext::WRITE) {
- scariness.Scare(30, "wild-addr-write");
- } else if (write_flag == SignalContext::READ) {
- scariness.Scare(20, "wild-addr-read");
- } else {
- scariness.Scare(25, "wild-addr");
- }
- } else {
+ if (signal.IsStackOverflow()) {
+ scariness.Scare(10, "stack-overflow");
+ } else if (!signal.is_memory_access) {
scariness.Scare(10, "signal");
+ } else if (signal.addr < GetPageSizeCached()) {
+ scariness.Scare(10, "null-deref");
+ } else if (signal.addr == signal.pc) {
+ scariness.Scare(60, "wild-jump");
+ } else if (signal.write_flag == SignalContext::WRITE) {
+ scariness.Scare(30, "wild-addr-write");
+ } else if (signal.write_flag == SignalContext::READ) {
+ scariness.Scare(20, "wild-addr-read");
+ } else {
+ scariness.Scare(25, "wild-addr");
}
}
void Print();
@@ -104,17 +71,19 @@ struct ErrorDoubleFree : ErrorBase {
void Print();
};
-struct ErrorNewDeleteSizeMismatch : ErrorBase {
- // ErrorNewDeleteSizeMismatch doesn't own the stack trace.
+struct ErrorNewDeleteTypeMismatch : ErrorBase {
+ // ErrorNewDeleteTypeMismatch doesn't own the stack trace.
const BufferedStackTrace *free_stack;
HeapAddressDescription addr_description;
uptr delete_size;
+ uptr delete_alignment;
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
// constructor
- ErrorNewDeleteSizeMismatch() = default;
- ErrorNewDeleteSizeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
- uptr delete_size_)
- : ErrorBase(tid), free_stack(stack), delete_size(delete_size_) {
+ ErrorNewDeleteTypeMismatch() = default;
+ ErrorNewDeleteTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
+ uptr delete_size_, uptr delete_alignment_)
+ : ErrorBase(tid), free_stack(stack), delete_size(delete_size_),
+ delete_alignment(delete_alignment_) {
GetHeapAddressInformation(addr, 1, &addr_description);
scariness.Clear();
scariness.Scare(10, "new-delete-type-mismatch");
@@ -324,10 +293,9 @@ struct ErrorGeneric : ErrorBase {
// clang-format off
#define ASAN_FOR_EACH_ERROR_KIND(macro) \
- macro(StackOverflow) \
macro(DeadlySignal) \
macro(DoubleFree) \
- macro(NewDeleteSizeMismatch) \
+ macro(NewDeleteTypeMismatch) \
macro(FreeNotMalloced) \
macro(AllocTypeMismatch) \
macro(MallocUsableSizeNotOwned) \
diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc
index 017b7d2af129..1c6184e3c7fc 100644
--- a/lib/asan/asan_fake_stack.cc
+++ b/lib/asan/asan_fake_stack.cc
@@ -28,9 +28,9 @@ static const u64 kAllocaRedzoneMask = 31UL;
// For small size classes inline PoisonShadow for better performance.
ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
- CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3.
u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
- if (class_id <= 6) {
+ if (SHADOW_SCALE == 3 && class_id <= 6) {
+ // This code expects SHADOW_SCALE=3.
for (uptr i = 0; i < (((uptr)1) << class_id); i++) {
shadow[i] = magic;
// Make sure this does not become memset.
@@ -171,7 +171,7 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
}
}
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
static THREADLOCAL FakeStack *fake_stack_tls;
FakeStack *GetTLSFakeStack() {
@@ -183,7 +183,7 @@ void SetTLSFakeStack(FakeStack *fs) {
#else
FakeStack *GetTLSFakeStack() { return 0; }
void SetTLSFakeStack(FakeStack *fs) { }
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
static FakeStack *GetFakeStack() {
AsanThread *t = GetCurrentThread();
diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc
index 6be0d6e94b9a..562168e6d428 100644
--- a/lib/asan/asan_flags.cc
+++ b/lib/asan/asan_flags.cc
@@ -118,6 +118,10 @@ void InitializeFlags() {
const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
ubsan_parser.ParseString(ubsan_default_options);
#endif
+#if CAN_SANITIZE_LEAKS
+ const char *lsan_default_options = __lsan::MaybeCallLsanDefaultOptions();
+ lsan_parser.ParseString(lsan_default_options);
+#endif
// Override from command line.
asan_parser.ParseString(GetEnv("ASAN_OPTIONS"));
@@ -144,6 +148,9 @@ void InitializeFlags() {
SanitizerToolName);
Die();
}
+ // Ensure that redzone is at least SHADOW_GRANULARITY.
+ if (f->redzone < (int)SHADOW_GRANULARITY)
+ f->redzone = SHADOW_GRANULARITY;
// Make "strict_init_order" imply "check_initialization_order".
// TODO(samsonov): Use a single runtime flag for an init-order checker.
if (f->strict_init_order) {
diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc
index f2216c2e9b3b..00071d39f041 100644
--- a/lib/asan/asan_flags.inc
+++ b/lib/asan/asan_flags.inc
@@ -79,6 +79,10 @@ ASAN_FLAG(
"Number of seconds to sleep between printing an error report and "
"terminating the program. Useful for debugging purposes (e.g. when one "
"needs to attach gdb).")
+ASAN_FLAG(
+ int, sleep_after_init, 0,
+ "Number of seconds to sleep after AddressSanitizer is initialized. "
+ "Useful for debugging purposes (e.g. when one needs to attach gdb).")
ASAN_FLAG(bool, check_malloc_usable_size, true,
"Allows the users to work around the bug in Nvidia drivers prior to "
"295.*.")
@@ -143,11 +147,6 @@ ASAN_FLAG(int, detect_odr_violation, 2,
"If >=2, detect violation of One-Definition-Rule (ODR); "
"If ==1, detect ODR-violation only if the two variables "
"have different sizes")
-ASAN_FLAG(bool, dump_instruction_bytes, false,
- "If true, dump 16 bytes starting at the instruction that caused SEGV")
-ASAN_FLAG(bool, dump_registers, true,
- "If true, dump values of CPU registers when SEGV happens. Only "
- "available on OS X for now.")
ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
ASAN_FLAG(bool, halt_on_error, true,
"Crash the program after printing the first error report "
diff --git a/lib/asan/asan_fuchsia.cc b/lib/asan/asan_fuchsia.cc
new file mode 100644
index 000000000000..0b5bff4f565e
--- /dev/null
+++ b/lib/asan/asan_fuchsia.cc
@@ -0,0 +1,218 @@
+//===-- asan_fuchsia.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Fuchsia-specific details.
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_fuchsia.h"
+#if SANITIZER_FUCHSIA
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+
+#include <limits.h>
+#include <zircon/sanitizer.h>
+#include <zircon/syscalls.h>
+#include <zircon/threads.h>
+
+namespace __asan {
+
+// The system already set up the shadow memory for us.
+// __sanitizer::GetMaxUserVirtualAddress has already been called by
+// AsanInitInternal->InitializeHighMemEnd (asan_rtl.cc).
+// Just do some additional sanity checks here.
+void InitializeShadowMemory() {
+ if (Verbosity()) PrintAddressSpaceLayout();
+
+ // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address.
+ __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
+ DCHECK(kLowShadowBeg != kDefaultShadowSentinel);
+ __asan_shadow_memory_dynamic_address = kLowShadowBeg;
+
+ CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
+ CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1);
+ CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit);
+ CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base);
+ CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1);
+ CHECK_EQ(kLowShadowEnd, 0);
+ CHECK_EQ(kLowShadowBeg, 0);
+}
+
+void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
+ UNIMPLEMENTED();
+}
+
+void AsanCheckDynamicRTPrereqs() {}
+void AsanCheckIncompatibleRT() {}
+void InitializeAsanInterceptors() {}
+
+void *AsanDoesNotSupportStaticLinkage() { return nullptr; }
+
+void InitializePlatformExceptionHandlers() {}
+void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+ UNIMPLEMENTED();
+}
+
+// We can use a plain thread_local variable for TSD.
+static thread_local void *per_thread;
+
+void *AsanTSDGet() { return per_thread; }
+
+void AsanTSDSet(void *tsd) { per_thread = tsd; }
+
+// There's no initialization needed, and the passed-in destructor
+// will never be called. Instead, our own thread destruction hook
+// (below) will call AsanThread::TSDDtor directly.
+void AsanTSDInit(void (*destructor)(void *tsd)) {
+ DCHECK(destructor == &PlatformTSDDtor);
+}
+
+void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
+
+static inline size_t AsanThreadMmapSize() {
+ return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
+}
+
+struct AsanThread::InitOptions {
+ uptr stack_bottom, stack_size;
+};
+
+// Shared setup between thread creation and startup for the initial thread.
+static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
+ uptr user_id, bool detached,
+ const char *name, uptr stack_bottom,
+ uptr stack_size) {
+ // In lieu of AsanThread::Create.
+ AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
+
+ AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
+ u32 tid =
+ asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args);
+ asanThreadRegistry().SetThreadName(tid, name);
+
+ // On other systems, AsanThread::Init() is called from the new
+ // thread itself. But on Fuchsia we already know the stack address
+ // range beforehand, so we can do most of the setup right now.
+ const AsanThread::InitOptions options = {stack_bottom, stack_size};
+ thread->Init(&options);
+
+ return thread;
+}
+
+// This gets the same arguments passed to Init by CreateAsanThread, above.
+// We're in the creator thread before the new thread is actually started,
+// but its stack address range is already known. We don't bother tracking
+// the static TLS address range because the system itself already uses an
+// ASan-aware allocator for that.
+void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) {
+ DCHECK_NE(GetCurrentThread(), this);
+ DCHECK_NE(GetCurrentThread(), nullptr);
+ CHECK_NE(options->stack_bottom, 0);
+ CHECK_NE(options->stack_size, 0);
+ stack_bottom_ = options->stack_bottom;
+ stack_top_ = options->stack_bottom + options->stack_size;
+}
+
+// Called by __asan::AsanInitInternal (asan_rtl.c).
+AsanThread *CreateMainThread() {
+ thrd_t self = thrd_current();
+ char name[ZX_MAX_NAME_LEN];
+ CHECK_NE(__sanitizer::MainThreadStackBase, 0);
+ CHECK_GT(__sanitizer::MainThreadStackSize, 0);
+ AsanThread *t = CreateAsanThread(
+ nullptr, 0, reinterpret_cast<uptr>(self), true,
+ _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name,
+ sizeof(name)) == ZX_OK
+ ? name
+ : nullptr,
+ __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize);
+ SetCurrentThread(t);
+ return t;
+}
+
+// This is called before each thread creation is attempted. So, in
+// its first call, the calling thread is the initial and sole thread.
+static void *BeforeThreadCreateHook(uptr user_id, bool detached,
+ const char *name, uptr stack_bottom,
+ uptr stack_size) {
+ EnsureMainThreadIDIsCorrect();
+ // Strict init-order checking is thread-hostile.
+ if (flags()->strict_init_order) StopInitOrderChecking();
+
+ GET_STACK_TRACE_THREAD;
+ u32 parent_tid = GetCurrentTidOrInvalid();
+
+ return CreateAsanThread(&stack, parent_tid, user_id, detached, name,
+ stack_bottom, stack_size);
+}
+
+// This is called after creating a new thread (in the creating thread),
+// with the pointer returned by BeforeThreadCreateHook (above).
+static void ThreadCreateHook(void *hook, bool aborted) {
+ AsanThread *thread = static_cast<AsanThread *>(hook);
+ if (!aborted) {
+ // The thread was created successfully.
+ // ThreadStartHook is already running in the new thread.
+ } else {
+ // The thread wasn't created after all.
+ // Clean up everything we set up in BeforeThreadCreateHook.
+ asanThreadRegistry().FinishThread(thread->tid());
+ UnmapOrDie(thread, AsanThreadMmapSize());
+ }
+}
+
+// This is called in the newly-created thread before it runs anything else,
+// with the pointer returned by BeforeThreadCreateHook (above).
+// cf. asan_interceptors.cc:asan_thread_start
+static void ThreadStartHook(void *hook, uptr os_id) {
+ AsanThread *thread = static_cast<AsanThread *>(hook);
+ SetCurrentThread(thread);
+
+ // In lieu of AsanThread::ThreadStart.
+ asanThreadRegistry().StartThread(thread->tid(), os_id, /*workerthread*/ false,
+ nullptr);
+}
+
+// Each thread runs this just before it exits,
+// with the pointer returned by BeforeThreadCreateHook (above).
+// All per-thread destructors have already been called.
+static void ThreadExitHook(void *hook, uptr os_id) {
+ AsanThread::TSDDtor(per_thread);
+}
+
+} // namespace __asan
+
+// These are declared (in extern "C") by <zircon/sanitizer.h>.
+// The system runtime will call our definitions directly.
+
+void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
+ const char *name, void *stack_base,
+ size_t stack_size) {
+ return __asan::BeforeThreadCreateHook(
+ reinterpret_cast<uptr>(thread), detached, name,
+ reinterpret_cast<uptr>(stack_base), stack_size);
+}
+
+void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
+ __asan::ThreadCreateHook(hook, error != thrd_success);
+}
+
+void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
+ __asan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
+}
+
+void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
+ __asan::ThreadExitHook(hook, reinterpret_cast<uptr>(self));
+}
+
+#endif // SANITIZER_FUCHSIA
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index eebada804f07..0db65d010349 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -384,6 +384,10 @@ void __asan_register_globals(__asan_global *globals, uptr n) {
}
RegisterGlobal(&globals[i]);
}
+
+ // Poison the metadata. It should not be accessible to user code.
+ PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global),
+ kAsanGlobalRedzoneMagic);
}
// Unregister an array of globals.
@@ -399,6 +403,9 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) {
}
UnregisterGlobal(&globals[i]);
}
+
+ // Unpoison the metadata.
+ PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global), 0);
}
// This method runs immediately prior to dynamic initialization in each TU,
diff --git a/lib/asan/asan_init_version.h b/lib/asan/asan_init_version.h
index f48cc19cc515..c49fcd740248 100644
--- a/lib/asan/asan_init_version.h
+++ b/lib/asan/asan_init_version.h
@@ -15,6 +15,8 @@
#ifndef ASAN_INIT_VERSION_H
#define ASAN_INIT_VERSION_H
+#include "sanitizer_common/sanitizer_platform.h"
+
extern "C" {
// Every time the ASan ABI changes we also change the version number in the
// __asan_init function name. Objects built with incompatible ASan ABI
@@ -32,7 +34,12 @@ extern "C" {
// v6=>v7: added 'odr_indicator' to __asan_global
// v7=>v8: added '__asan_(un)register_image_globals' functions for dead
// stripping support on Mach-O platforms
+#if SANITIZER_WORDSIZE == 32 && SANITIZER_ANDROID
+ // v8=>v9: 32-bit Android switched to dynamic shadow
+ #define __asan_version_mismatch_check __asan_version_mismatch_check_v9
+#else
#define __asan_version_mismatch_check __asan_version_mismatch_check_v8
+#endif
}
#endif // ASAN_INIT_VERSION_H
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 34ca22b8616e..cb7dcb3b1ca8 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -24,6 +24,11 @@
#include "lsan/lsan_common.h"
#include "sanitizer_common/sanitizer_libc.h"
+// There is no general interception at all on Fuchsia.
+// Only the functions in asan_interceptors_memintrinsics.cc are
+// really defined to replace libc functions.
+#if !SANITIZER_FUCHSIA
+
#if SANITIZER_POSIX
#include "sanitizer_common/sanitizer_posix.h"
#endif
@@ -36,108 +41,6 @@
namespace __asan {
-// Return true if we can quickly decide that the region is unpoisoned.
-// We assume that a redzone is at least 16 bytes.
-static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
- if (size == 0) return true;
- if (size <= 32)
- return !AddressIsPoisoned(beg) &&
- !AddressIsPoisoned(beg + size - 1) &&
- !AddressIsPoisoned(beg + size / 2);
- if (size <= 64)
- return !AddressIsPoisoned(beg) &&
- !AddressIsPoisoned(beg + size / 4) &&
- !AddressIsPoisoned(beg + size - 1) &&
- !AddressIsPoisoned(beg + 3 * size / 4) &&
- !AddressIsPoisoned(beg + size / 2);
- return false;
-}
-
-struct AsanInterceptorContext {
- const char *interceptor_name;
-};
-
-// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
-// and ASAN_WRITE_RANGE as macro instead of function so
-// that no extra frames are created, and stack trace contains
-// relevant information only.
-// We check all shadow bytes.
-#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
- uptr __offset = (uptr)(offset); \
- uptr __size = (uptr)(size); \
- uptr __bad = 0; \
- if (__offset > __offset + __size) { \
- GET_STACK_TRACE_FATAL_HERE; \
- ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
- } \
- if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
- (__bad = __asan_region_is_poisoned(__offset, __size))) { \
- AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
- bool suppressed = false; \
- if (_ctx) { \
- suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
- if (!suppressed && HaveStackTraceBasedSuppressions()) { \
- GET_STACK_TRACE_FATAL_HERE; \
- suppressed = IsStackTraceSuppressed(&stack); \
- } \
- } \
- if (!suppressed) { \
- GET_CURRENT_PC_BP_SP; \
- ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
- } \
- } \
- } while (0)
-
-// memcpy is called during __asan_init() from the internals of printf(...).
-// We do not treat memcpy with to==from as a bug.
-// See http://llvm.org/bugs/show_bug.cgi?id=11763.
-#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \
- do { \
- if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
- if (asan_init_is_running) { \
- return REAL(memcpy)(to, from, size); \
- } \
- ENSURE_ASAN_INITED(); \
- if (flags()->replace_intrin) { \
- if (to != from) { \
- CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
- } \
- ASAN_READ_RANGE(ctx, from, size); \
- ASAN_WRITE_RANGE(ctx, to, size); \
- } \
- return REAL(memcpy)(to, from, size); \
- } while (0)
-
-// memset is called inside Printf.
-#define ASAN_MEMSET_IMPL(ctx, block, c, size) \
- do { \
- if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
- if (asan_init_is_running) { \
- return REAL(memset)(block, c, size); \
- } \
- ENSURE_ASAN_INITED(); \
- if (flags()->replace_intrin) { \
- ASAN_WRITE_RANGE(ctx, block, size); \
- } \
- return REAL(memset)(block, c, size); \
- } while (0)
-
-#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \
- do { \
- if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \
- ENSURE_ASAN_INITED(); \
- if (flags()->replace_intrin) { \
- ASAN_READ_RANGE(ctx, from, size); \
- ASAN_WRITE_RANGE(ctx, to, size); \
- } \
- return internal_memmove(to, from, size); \
- } while (0)
-
-#define ASAN_READ_RANGE(ctx, offset, size) \
- ACCESS_MEMORY_RANGE(ctx, offset, size, false)
-#define ASAN_WRITE_RANGE(ctx, offset, size) \
- ACCESS_MEMORY_RANGE(ctx, offset, size, true)
-
#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
ASAN_READ_RANGE((ctx), (s), \
common_flags()->strict_string_checks ? (len) + 1 : (n))
@@ -145,23 +48,6 @@ struct AsanInterceptorContext {
#define ASAN_READ_STRING(ctx, s, n) \
ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
-// Behavior of functions like "memcpy" or "strcpy" is undefined
-// if memory intervals overlap. We report error in this case.
-// Macro is used to avoid creation of new frames.
-static inline bool RangesOverlap(const char *offset1, uptr length1,
- const char *offset2, uptr length2) {
- return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
-}
-#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
- const char *offset1 = (const char*)_offset1; \
- const char *offset2 = (const char*)_offset2; \
- if (RangesOverlap(offset1, length1, offset2, length2)) { \
- GET_STACK_TRACE_FATAL_HERE; \
- ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
- offset2, length2, &stack); \
- } \
-} while (0)
-
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
#if SANITIZER_INTERCEPT_STRNLEN
if (REAL(strnlen)) {
@@ -275,6 +161,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} while (false)
#include "sanitizer_common/sanitizer_common_interceptors.inc"
+#include "sanitizer_common/sanitizer_signal_interceptors.inc"
// Syscall interceptors don't have contexts, we don't support suppressions
// for them.
@@ -356,42 +243,6 @@ INTERCEPTOR(int, pthread_join, void *t, void **arg) {
DEFINE_REAL_PTHREAD_FUNCTIONS
#endif // ASAN_INTERCEPT_PTHREAD_CREATE
-#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
-
-#if SANITIZER_ANDROID
-INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
- if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
- return REAL(bsd_signal)(signum, handler);
- return 0;
-}
-#endif
-
-INTERCEPTOR(void*, signal, int signum, void *handler) {
- if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
- return REAL(signal)(signum, handler);
- return nullptr;
-}
-
-INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
- struct sigaction *oldact) {
- if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
- return REAL(sigaction)(signum, act, oldact);
- return 0;
-}
-
-namespace __sanitizer {
-int real_sigaction(int signum, const void *act, void *oldact) {
- return REAL(sigaction)(signum, (const struct sigaction *)act,
- (struct sigaction *)oldact);
-}
-} // namespace __sanitizer
-
-#elif SANITIZER_POSIX
-// We need to have defined REAL(sigaction) on posix systems.
-DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
- struct sigaction *oldact)
-#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
-
#if ASAN_INTERCEPT_SWAPCONTEXT
static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
// Align to page size.
@@ -428,6 +279,11 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
}
#endif // ASAN_INTERCEPT_SWAPCONTEXT
+#if SANITIZER_NETBSD
+#define longjmp __longjmp14
+#define siglongjmp __siglongjmp14
+#endif
+
INTERCEPTOR(void, longjmp, void *env, int val) {
__asan_handle_no_return();
REAL(longjmp)(env, val);
@@ -462,18 +318,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
}
#endif
-void *__asan_memcpy(void *to, const void *from, uptr size) {
- ASAN_MEMCPY_IMPL(nullptr, to, from, size);
-}
-
-void *__asan_memset(void *block, int c, uptr size) {
- ASAN_MEMSET_IMPL(nullptr, block, c, size);
-}
-
-void *__asan_memmove(void *to, const void *from, uptr size) {
- ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
-}
-
#if ASAN_INTERCEPT_INDEX
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
INTERCEPTOR(char*, index, const char *string, int c)
@@ -711,6 +555,7 @@ void InitializeAsanInterceptors() {
CHECK(!was_called_once);
was_called_once = true;
InitializeCommonInterceptors();
+ InitializeSignalInterceptors();
// Intercept str* functions.
ASAN_INTERCEPT_FUNC(strcat); // NOLINT
@@ -733,15 +578,9 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(strtoll);
#endif
- // Intecept signal- and jump-related functions.
+ // Intecept jump-related functions.
ASAN_INTERCEPT_FUNC(longjmp);
-#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
- ASAN_INTERCEPT_FUNC(sigaction);
-#if SANITIZER_ANDROID
- ASAN_INTERCEPT_FUNC(bsd_signal);
-#endif
- ASAN_INTERCEPT_FUNC(signal);
-#endif
+
#if ASAN_INTERCEPT_SWAPCONTEXT
ASAN_INTERCEPT_FUNC(swapcontext);
#endif
@@ -785,3 +624,5 @@ void InitializeAsanInterceptors() {
}
} // namespace __asan
+
+#endif // !SANITIZER_FUCHSIA
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index 93fca4f67366..e13bdecfdede 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -15,9 +15,30 @@
#define ASAN_INTERCEPTORS_H
#include "asan_internal.h"
+#include "asan_interceptors_memintrinsics.h"
#include "interception/interception.h"
#include "sanitizer_common/sanitizer_platform_interceptors.h"
+namespace __asan {
+
+void InitializeAsanInterceptors();
+void InitializePlatformInterceptors();
+
+#define ENSURE_ASAN_INITED() \
+ do { \
+ CHECK(!asan_init_is_running); \
+ if (UNLIKELY(!asan_inited)) { \
+ AsanInitFromRtl(); \
+ } \
+ } while (0)
+
+} // namespace __asan
+
+// There is no general interception at all on Fuchsia.
+// Only the functions in asan_interceptors_memintrinsics.h are
+// really defined to replace libc functions.
+#if !SANITIZER_FUCHSIA
+
// Use macro to describe if specific function should be
// intercepted on a given platform.
#if !SANITIZER_WINDOWS
@@ -34,25 +55,20 @@
# define ASAN_INTERCEPT_FORK 0
#endif
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
+ SANITIZER_SOLARIS
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
#else
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
# define ASAN_INTERCEPT_SWAPCONTEXT 1
#else
# define ASAN_INTERCEPT_SWAPCONTEXT 0
#endif
#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
-#else
-# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
-#endif
-
-#if !SANITIZER_WINDOWS
# define ASAN_INTERCEPT_SIGLONGJMP 1
#else
# define ASAN_INTERCEPT_SIGLONGJMP 0
@@ -66,7 +82,8 @@
// Android bug: https://code.google.com/p/android/issues/detail?id=61799
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
- !(SANITIZER_ANDROID && defined(__i386))
+ !(SANITIZER_ANDROID && defined(__i386)) && \
+ !SANITIZER_SOLARIS
# define ASAN_INTERCEPT___CXA_THROW 1
#else
# define ASAN_INTERCEPT___CXA_THROW 0
@@ -85,16 +102,11 @@
#endif
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
-DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
-DECLARE_REAL(void*, memset, void *block, int c, uptr size)
DECLARE_REAL(char*, strchr, const char *str, int c)
DECLARE_REAL(SIZE_T, strlen, const char *s)
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
-struct sigaction;
-DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
- struct sigaction *oldact)
#if !SANITIZER_MAC
#define ASAN_INTERCEPT_FUNC(name) \
@@ -113,18 +125,6 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
#define ASAN_INTERCEPT_FUNC(name)
#endif // SANITIZER_MAC
-namespace __asan {
-
-void InitializeAsanInterceptors();
-void InitializePlatformInterceptors();
-
-#define ENSURE_ASAN_INITED() do { \
- CHECK(!asan_init_is_running); \
- if (UNLIKELY(!asan_inited)) { \
- AsanInitFromRtl(); \
- } \
-} while (0)
-
-} // namespace __asan
+#endif // !SANITIZER_FUCHSIA
#endif // ASAN_INTERCEPTORS_H
diff --git a/lib/asan/asan_interceptors_memintrinsics.cc b/lib/asan/asan_interceptors_memintrinsics.cc
new file mode 100644
index 000000000000..c89cb011492e
--- /dev/null
+++ b/lib/asan/asan_interceptors_memintrinsics.cc
@@ -0,0 +1,44 @@
+//===-- asan_interceptors_memintrinsics.cc --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan versions of memcpy, memmove, and memset.
+//===---------------------------------------------------------------------===//
+
+#include "asan_interceptors_memintrinsics.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_suppressions.h"
+
+using namespace __asan; // NOLINT
+
+void *__asan_memcpy(void *to, const void *from, uptr size) {
+ ASAN_MEMCPY_IMPL(nullptr, to, from, size);
+}
+
+void *__asan_memset(void *block, int c, uptr size) {
+ ASAN_MEMSET_IMPL(nullptr, block, c, size);
+}
+
+void *__asan_memmove(void *to, const void *from, uptr size) {
+ ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
+}
+
+#if SANITIZER_FUCHSIA
+
+// Fuchsia doesn't use sanitizer_common_interceptors.inc, but the only
+// things there it wants are these three. Just define them as aliases
+// here rather than repeating the contents.
+
+decltype(memcpy) memcpy[[gnu::alias("__asan_memcpy")]];
+decltype(memmove) memmove[[gnu::alias("__asan_memmove")]];
+decltype(memset) memset[[gnu::alias("__asan_memset")]];
+
+#endif // SANITIZER_FUCHSIA
diff --git a/lib/asan/asan_interceptors_memintrinsics.h b/lib/asan/asan_interceptors_memintrinsics.h
new file mode 100644
index 000000000000..5a8339a23e97
--- /dev/null
+++ b/lib/asan/asan_interceptors_memintrinsics.h
@@ -0,0 +1,148 @@
+//===-- asan_interceptors_memintrinsics.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_memintrin.cc
+//===---------------------------------------------------------------------===//
+#ifndef ASAN_MEMINTRIN_H
+#define ASAN_MEMINTRIN_H
+
+#include "asan_interface_internal.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "interception/interception.h"
+
+DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
+DECLARE_REAL(void*, memset, void *block, int c, uptr size)
+
+namespace __asan {
+
+// Return true if we can quickly decide that the region is unpoisoned.
+// We assume that a redzone is at least 16 bytes.
+static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
+ if (size == 0) return true;
+ if (size <= 32)
+ return !AddressIsPoisoned(beg) &&
+ !AddressIsPoisoned(beg + size - 1) &&
+ !AddressIsPoisoned(beg + size / 2);
+ if (size <= 64)
+ return !AddressIsPoisoned(beg) &&
+ !AddressIsPoisoned(beg + size / 4) &&
+ !AddressIsPoisoned(beg + size - 1) &&
+ !AddressIsPoisoned(beg + 3 * size / 4) &&
+ !AddressIsPoisoned(beg + size / 2);
+ return false;
+}
+
+struct AsanInterceptorContext {
+ const char *interceptor_name;
+};
+
+// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
+// and ASAN_WRITE_RANGE as macro instead of function so
+// that no extra frames are created, and stack trace contains
+// relevant information only.
+// We check all shadow bytes.
+#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
+ uptr __offset = (uptr)(offset); \
+ uptr __size = (uptr)(size); \
+ uptr __bad = 0; \
+ if (__offset > __offset + __size) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
+ } \
+ if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
+ (__bad = __asan_region_is_poisoned(__offset, __size))) { \
+ AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
+ bool suppressed = false; \
+ if (_ctx) { \
+ suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
+ if (!suppressed && HaveStackTraceBasedSuppressions()) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ suppressed = IsStackTraceSuppressed(&stack); \
+ } \
+ } \
+ if (!suppressed) { \
+ GET_CURRENT_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
+ } \
+ } \
+ } while (0)
+
+// memcpy is called during __asan_init() from the internals of printf(...).
+// We do not treat memcpy with to==from as a bug.
+// See http://llvm.org/bugs/show_bug.cgi?id=11763.
+#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \
+ do { \
+ if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
+ if (asan_init_is_running) { \
+ return REAL(memcpy)(to, from, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ if (to != from) { \
+ CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
+ } \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return REAL(memcpy)(to, from, size); \
+ } while (0)
+
+// memset is called inside Printf.
+#define ASAN_MEMSET_IMPL(ctx, block, c, size) \
+ do { \
+ if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
+ if (asan_init_is_running) { \
+ return REAL(memset)(block, c, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_WRITE_RANGE(ctx, block, size); \
+ } \
+ return REAL(memset)(block, c, size); \
+ } while (0)
+
+#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \
+ do { \
+ if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return internal_memmove(to, from, size); \
+ } while (0)
+
+#define ASAN_READ_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, false)
+#define ASAN_WRITE_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, true)
+
+// Behavior of functions like "memcpy" or "strcpy" is undefined
+// if memory intervals overlap. We report error in this case.
+// Macro is used to avoid creation of new frames.
+static inline bool RangesOverlap(const char *offset1, uptr length1,
+ const char *offset2, uptr length2) {
+ return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
+}
+#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
+ const char *offset1 = (const char*)_offset1; \
+ const char *offset2 = (const char*)_offset2; \
+ if (RangesOverlap(offset1, length1, offset2, length2)) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
+ offset2, length2, &stack); \
+ } \
+} while (0)
+
+} // namespace __asan
+
+#endif // ASAN_MEMINTRIN_H
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index f09bbd83af25..19133e5291a9 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -69,8 +69,12 @@ void InitializePlatformExceptionHandlers();
bool IsSystemHeapAddress(uptr addr);
// asan_rtl.cc
+void PrintAddressSpaceLayout();
void NORETURN ShowStatsAndAbort();
+// asan_shadow_setup.cc
+void InitializeShadowMemory();
+
// asan_malloc_linux.cc / asan_malloc_mac.cc
void ReplaceSystemMalloc();
@@ -80,6 +84,9 @@ void *AsanDoesNotSupportStaticLinkage();
void AsanCheckDynamicRTPrereqs();
void AsanCheckIncompatibleRT();
+// asan_thread.cc
+AsanThread *CreateMainThread();
+
// Support function for __asan_(un)register_image_globals. Searches for the
// loaded image containing `needle' and then enumerates all global metadata
// structures declared in that image, applying `op' (e.g.,
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 6d47ba432a61..047e1dbb72fa 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -13,10 +13,12 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
+ SANITIZER_SOLARIS
#include "asan_interceptors.h"
#include "asan_internal.h"
+#include "asan_premap_shadow.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_freebsd.h"
@@ -39,9 +41,17 @@
#include <sys/link_elf.h>
#endif
-#if SANITIZER_ANDROID || SANITIZER_FREEBSD
+#if SANITIZER_SOLARIS
+#include <link.h>
+#endif
+
+#if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
#include <ucontext.h>
extern "C" void* _DYNAMIC;
+#elif SANITIZER_NETBSD
+#include <link_elf.h>
+#include <ucontext.h>
+extern Elf_Dyn _DYNAMIC;
#else
#include <sys/ucontext.h>
#include <link.h>
@@ -77,9 +87,51 @@ void *AsanDoesNotSupportStaticLinkage() {
return &_DYNAMIC; // defined in link.h
}
+static void UnmapFromTo(uptr from, uptr to) {
+ CHECK(to >= from);
+ if (to == from) return;
+ uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
+ if (UNLIKELY(internal_iserror(res))) {
+ Report(
+ "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address "
+ "%p\n",
+ to - from, to - from, from);
+ CHECK("unable to unmap" && 0);
+ }
+}
+
+#if ASAN_PREMAP_SHADOW
+uptr FindPremappedShadowStart() {
+ uptr granularity = GetMmapGranularity();
+ uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
+ uptr premap_shadow_size = PremapShadowSize();
+ uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
+ // We may have mapped too much. Release extra memory.
+ UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
+ return shadow_start;
+}
+#endif
+
uptr FindDynamicShadowStart() {
- UNREACHABLE("FindDynamicShadowStart is not available");
- return 0;
+#if ASAN_PREMAP_SHADOW
+ if (!PremapShadowFailed())
+ return FindPremappedShadowStart();
+#endif
+
+ uptr granularity = GetMmapGranularity();
+ uptr alignment = granularity * 8;
+ uptr left_padding = granularity;
+ uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
+ uptr map_size = shadow_size + left_padding + alignment;
+
+ uptr map_start = (uptr)MmapNoAccess(map_size);
+ CHECK_NE(map_start, ~(uptr)0);
+
+ uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
+ UnmapFromTo(map_start, shadow_start - left_padding);
+ UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
+
+ return shadow_start;
}
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
@@ -93,6 +145,9 @@ void AsanCheckIncompatibleRT() {}
#else
static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
void *data) {
+ VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n",
+ info->dlpi_name, info->dlpi_addr);
+
// Continue until the first dynamic library is found
if (!info->dlpi_name || info->dlpi_name[0] == 0)
return 0;
@@ -101,6 +156,21 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
return 0;
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
+ // Ignore first entry (the main program)
+ char **p = (char **)data;
+ if (!(*p)) {
+ *p = (char *)-1;
+ return 0;
+ }
+#endif
+
+#if SANITIZER_SOLARIS
+ // Ignore executable on Solaris
+ if (info->dlpi_addr == 0)
+ return 0;
+#endif
+
*(const char **)data = info->dlpi_name;
return 1;
}
@@ -179,4 +249,5 @@ void *AsanDlSymNext(const char *sym) {
} // namespace __asan
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
+ // SANITIZER_SOLARIS
diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index fd40f47db1c4..6697ff8764ed 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/lib/asan/asan_malloc_linux.cc
@@ -15,7 +15,8 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
+ SANITIZER_NETBSD || SANITIZER_SOLARIS
#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "asan_allocator.h"
@@ -30,9 +31,9 @@ static uptr allocated_for_dlsym;
static const uptr kDlsymAllocPoolSize = 1024;
static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
-static bool IsInDlsymAllocPool(const void *ptr) {
+static INLINE bool IsInDlsymAllocPool(const void *ptr) {
uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
- return off < sizeof(alloc_memory_for_dlsym);
+ return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]);
}
static void *AllocateFromLocalPool(uptr size_in_bytes) {
@@ -43,6 +44,26 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) {
return mem;
}
+static INLINE bool MaybeInDlsym() {
+ // Fuchsia doesn't use dlsym-based interceptors.
+ return !SANITIZER_FUCHSIA && asan_init_is_running;
+}
+
+static void *ReallocFromLocalPool(void *ptr, uptr size) {
+ const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
+ const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
+ void *new_ptr;
+ if (UNLIKELY(MaybeInDlsym())) {
+ new_ptr = AllocateFromLocalPool(size);
+ } else {
+ ENSURE_ASAN_INITED();
+ GET_STACK_TRACE_MALLOC;
+ new_ptr = asan_malloc(size, &stack);
+ }
+ internal_memcpy(new_ptr, ptr, copy_size);
+ return new_ptr;
+}
+
INTERCEPTOR(void, free, void *ptr) {
GET_STACK_TRACE_FREE;
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
@@ -60,7 +81,7 @@ INTERCEPTOR(void, cfree, void *ptr) {
#endif // SANITIZER_INTERCEPT_CFREE
INTERCEPTOR(void*, malloc, uptr size) {
- if (UNLIKELY(asan_init_is_running))
+ if (UNLIKELY(MaybeInDlsym()))
// Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
return AllocateFromLocalPool(size);
ENSURE_ASAN_INITED();
@@ -69,7 +90,7 @@ INTERCEPTOR(void*, malloc, uptr size) {
}
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
- if (UNLIKELY(asan_init_is_running))
+ if (UNLIKELY(MaybeInDlsym()))
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
return AllocateFromLocalPool(nmemb * size);
ENSURE_ASAN_INITED();
@@ -78,21 +99,9 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
}
INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
- if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
- const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
- const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
- void *new_ptr;
- if (UNLIKELY(asan_init_is_running)) {
- new_ptr = AllocateFromLocalPool(size);
- } else {
- ENSURE_ASAN_INITED();
- GET_STACK_TRACE_MALLOC;
- new_ptr = asan_malloc(size, &stack);
- }
- internal_memcpy(new_ptr, ptr, copy_size);
- return new_ptr;
- }
- if (UNLIKELY(asan_init_is_running))
+ if (UNLIKELY(IsInDlsymAllocPool(ptr)))
+ return ReallocFromLocalPool(ptr, size);
+ if (UNLIKELY(MaybeInDlsym()))
return AllocateFromLocalPool(size);
ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
@@ -226,4 +235,5 @@ void ReplaceSystemMalloc() {
} // namespace __asan
#endif // SANITIZER_ANDROID
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
+ // SANITIZER_NETBSD || SANITIZER_SOLARIS
diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h
index 695740cd982f..d3f360ffc969 100644
--- a/lib/asan/asan_mapping.h
+++ b/lib/asan/asan_mapping.h
@@ -115,6 +115,13 @@
// || `[0x40000000, 0x47ffffff]` || LowShadow ||
// || `[0x00000000, 0x3fffffff]` || LowMem ||
//
+// Shadow mapping on NetBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
+// || `[0x4feffffffe01, 0x7f7ffffff000]` || HighMem ||
+// || `[0x49fdffffffc0, 0x4feffffffe00]` || HighShadow ||
+// || `[0x480000000000, 0x49fdffffffbf]` || ShadowGap ||
+// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
+// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
+//
// Default Windows/i386 mapping:
// (the exact location of HighShadow/HighMem may vary depending
// on WoW64, /LARGEADDRESSAWARE, etc).
@@ -124,11 +131,16 @@
// || `[0x30000000, 0x35ffffff]` || LowShadow ||
// || `[0x00000000, 0x2fffffff]` || LowMem ||
+#if defined(ASAN_SHADOW_SCALE)
+static const u64 kDefaultShadowScale = ASAN_SHADOW_SCALE;
+#else
static const u64 kDefaultShadowScale = 3;
+#endif
static const u64 kDefaultShadowSentinel = ~(uptr)0;
static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
static const u64 kDefaultShadowOffset64 = 1ULL << 44;
-static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
+static const u64 kDefaultShort64bitShadowOffset =
+ 0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale); // < 2G.
static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
static const u64 kIosShadowOffset64 = 0x120200000;
static const u64 kIosSimShadowOffset32 = 1ULL << 30;
@@ -136,18 +148,20 @@ static const u64 kIosSimShadowOffset64 = kDefaultShadowOffset64;
static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
-static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
+static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
+static const u64 kNetBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
#define SHADOW_SCALE kDefaultShadowScale
-
-#if SANITIZER_WORDSIZE == 32
+#if SANITIZER_FUCHSIA
+# define SHADOW_OFFSET (0)
+#elif SANITIZER_WORDSIZE == 32
# if SANITIZER_ANDROID
-# define SHADOW_OFFSET (0)
+# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
# elif defined(__mips__)
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
# elif SANITIZER_FREEBSD
@@ -178,6 +192,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
# define SHADOW_OFFSET kSystemZ_ShadowOffset64
# elif SANITIZER_FREEBSD
# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
+# elif SANITIZER_NETBSD
+# define SHADOW_OFFSET kNetBSD_ShadowOffset64
# elif SANITIZER_MAC
# define SHADOW_OFFSET kDefaultShadowOffset64
# elif defined(__mips64)
@@ -189,6 +205,12 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
# endif
#endif
+#if SANITIZER_ANDROID && defined(__arm__)
+# define ASAN_PREMAP_SHADOW 1
+#else
+# define ASAN_PREMAP_SHADOW 0
+#endif
+
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
diff --git a/lib/asan/asan_memory_profile.cc b/lib/asan/asan_memory_profile.cc
index 05846c37cb6d..603284c8c688 100644
--- a/lib/asan/asan_memory_profile.cc
+++ b/lib/asan/asan_memory_profile.cc
@@ -107,6 +107,9 @@ static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
__lsan::ForEachChunk(ChunkCallback, &hp);
uptr *Arg = reinterpret_cast<uptr*>(argument);
hp.Print(Arg[0], Arg[1]);
+
+ if (Verbosity())
+ __asan_print_accumulated_stats();
}
} // namespace __asan
diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc
index e68c7f3e2400..072f027addd6 100644
--- a/lib/asan/asan_new_delete.cc
+++ b/lib/asan/asan_new_delete.cc
@@ -125,77 +125,69 @@ INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
}
-#endif
+#endif // !SANITIZER_MAC
#define OPERATOR_DELETE_BODY(type) \
GET_STACK_TRACE_FREE;\
- asan_free(ptr, &stack, type);
+ asan_delete(ptr, 0, 0, &stack, type);
+
+#define OPERATOR_DELETE_BODY_SIZE(type) \
+ GET_STACK_TRACE_FREE;\
+ asan_delete(ptr, size, 0, &stack, type);
+
+#define OPERATOR_DELETE_BODY_ALIGN(type) \
+ GET_STACK_TRACE_FREE;\
+ asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type);
+
+#define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \
+ GET_STACK_TRACE_FREE;\
+ asan_delete(ptr, size, static_cast<uptr>(align), &stack, type);
#if !SANITIZER_MAC
CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr) NOEXCEPT {
- OPERATOR_DELETE_BODY(FROM_NEW);
-}
+void operator delete(void *ptr) NOEXCEPT
+{ OPERATOR_DELETE_BODY(FROM_NEW); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr) NOEXCEPT {
- OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
+void operator delete[](void *ptr) NOEXCEPT
+{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, std::nothrow_t const&) {
- OPERATOR_DELETE_BODY(FROM_NEW);
-}
+void operator delete(void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FROM_NEW); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, std::nothrow_t const&) {
- OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
+void operator delete[](void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, size_t size) NOEXCEPT {
- GET_STACK_TRACE_FREE;
- asan_sized_free(ptr, size, &stack, FROM_NEW);
-}
+void operator delete(void *ptr, size_t size) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, size_t size) NOEXCEPT {
- GET_STACK_TRACE_FREE;
- asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
-}
+void operator delete[](void *ptr, size_t size) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, std::align_val_t) NOEXCEPT {
- OPERATOR_DELETE_BODY(FROM_NEW);
-}
+void operator delete(void *ptr, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, std::align_val_t) NOEXCEPT {
- OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
+void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&) {
- OPERATOR_DELETE_BODY(FROM_NEW);
-}
+void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&) {
- OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
+void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT {
- GET_STACK_TRACE_FREE;
- asan_sized_free(ptr, size, &stack, FROM_NEW);
-}
+void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); }
CXX_OPERATOR_ATTRIBUTE
-void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT {
- GET_STACK_TRACE_FREE;
- asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
-}
+void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT
+{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); }
#else // SANITIZER_MAC
-INTERCEPTOR(void, _ZdlPv, void *ptr) {
- OPERATOR_DELETE_BODY(FROM_NEW);
-}
-INTERCEPTOR(void, _ZdaPv, void *ptr) {
- OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
-INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
- OPERATOR_DELETE_BODY(FROM_NEW);
-}
-INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
- OPERATOR_DELETE_BODY(FROM_NEW_BR);
-}
-#endif
+INTERCEPTOR(void, _ZdlPv, void *ptr)
+{ OPERATOR_DELETE_BODY(FROM_NEW); }
+INTERCEPTOR(void, _ZdaPv, void *ptr)
+{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
+INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FROM_NEW); }
+INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
+#endif // !SANITIZER_MAC
diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc
index abb75ab3bf92..c3a82aa0049e 100644
--- a/lib/asan/asan_poisoning.cc
+++ b/lib/asan/asan_poisoning.cc
@@ -217,7 +217,7 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
uptr __bad = __asan_region_is_poisoned(__p, __size); \
__asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\
} \
- } while (false); \
+ } while (false)
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h
index cc3281e08a71..1e00070bcf63 100644
--- a/lib/asan/asan_poisoning.h
+++ b/lib/asan/asan_poisoning.h
@@ -46,8 +46,11 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
// for mapping shadow and zeroing out pages doesn't "just work", so we should
// probably provide higher-level interface for these operations.
// For now, just memset on Windows.
- if (value ||
- SANITIZER_WINDOWS == 1 ||
+ if (value || SANITIZER_WINDOWS == 1 ||
+ // TODO(mcgrathr): Fuchsia doesn't allow the shadow mapping to be
+ // changed at all. It doesn't currently have an efficient means
+ // to zero a bunch of pages, but maybe we should add one.
+ SANITIZER_FUCHSIA == 1 ||
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
} else {
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index added746ace8..17c28b0aea2a 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -25,7 +25,6 @@
#include "sanitizer_common/sanitizer_procmaps.h"
#include <pthread.h>
-#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
@@ -34,58 +33,9 @@
namespace __asan {
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
- ScopedDeadlySignal signal_scope(GetCurrentThread());
- int code = (int)((siginfo_t*)siginfo)->si_code;
- // Write the first message using fd=2, just in case.
- // It may actually fail to write in case stderr is closed.
- internal_write(2, "ASAN:DEADLYSIGNAL\n", 18);
- SignalContext sig = SignalContext::Create(siginfo, context);
-
- // Access at a reasonable offset above SP, or slightly below it (to account
- // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
- // probably a stack overflow.
-#ifdef __s390__
- // On s390, the fault address in siginfo points to start of the page, not
- // to the precise word that was accessed. Mask off the low bits of sp to
- // take it into account.
- bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) &&
- sig.addr < sig.sp + 0xFFFF;
-#else
- bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
-#endif
-
-#if __powerpc__
- // Large stack frames can be allocated with e.g.
- // lis r0,-10000
- // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
- // If the store faults then sp will not have been updated, so test above
- // will not work, because the fault address will be more than just "slightly"
- // below sp.
- if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
- u32 inst = *(unsigned *)sig.pc;
- u32 ra = (inst >> 16) & 0x1F;
- u32 opcd = inst >> 26;
- u32 xo = (inst >> 1) & 0x3FF;
- // Check for store-with-update to sp. The instructions we accept are:
- // stbu rs,d(ra) stbux rs,ra,rb
- // sthu rs,d(ra) sthux rs,ra,rb
- // stwu rs,d(ra) stwux rs,ra,rb
- // stdu rs,ds(ra) stdux rs,ra,rb
- // where ra is r1 (the stack pointer).
- if (ra == 1 &&
- (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
- (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
- IsStackAccess = true;
- }
-#endif // __powerpc__
-
- // We also check si_code to filter out SEGV caused by something else other
- // then hitting the guard page or unmapped memory, like, for example,
- // unaligned memory access.
- if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
- ReportStackOverflow(sig);
- else
- ReportDeadlySignal(signo, sig);
+ StartReportDeadlySignal();
+ SignalContext sig(siginfo, context);
+ ReportDeadlySignal(sig);
}
// ---------------------- TSD ---------------- {{{1
diff --git a/lib/asan/asan_premap_shadow.cc b/lib/asan/asan_premap_shadow.cc
new file mode 100644
index 000000000000..229eba99fe0e
--- /dev/null
+++ b/lib/asan/asan_premap_shadow.cc
@@ -0,0 +1,79 @@
+//===-- asan_premap_shadow.cc ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Reserve shadow memory with an ifunc resolver.
+//===----------------------------------------------------------------------===//
+
+#include "asan_mapping.h"
+
+#if ASAN_PREMAP_SHADOW
+
+#include "asan_premap_shadow.h"
+#include "sanitizer_common/sanitizer_posix.h"
+
+namespace __asan {
+
+// The code in this file needs to run in an unrelocated binary. It may not
+// access any external symbol, including its own non-hidden globals.
+
+// Conservative upper limit.
+uptr PremapShadowSize() {
+ uptr granularity = GetMmapGranularity();
+ return RoundUpTo(GetMaxVirtualAddress() >> SHADOW_SCALE, granularity);
+}
+
+// Returns an address aligned to 8 pages, such that one page on the left and
+// PremapShadowSize() bytes on the right of it are mapped r/o.
+uptr PremapShadow() {
+ uptr granularity = GetMmapGranularity();
+ uptr alignment = granularity * 8;
+ uptr left_padding = granularity;
+ uptr shadow_size = PremapShadowSize();
+ uptr map_size = shadow_size + left_padding + alignment;
+
+ uptr map_start = (uptr)MmapNoAccess(map_size);
+ CHECK_NE(map_start, ~(uptr)0);
+
+ uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
+ uptr shadow_end = shadow_start + shadow_size;
+ internal_munmap(reinterpret_cast<void *>(map_start),
+ shadow_start - left_padding - map_start);
+ internal_munmap(reinterpret_cast<void *>(shadow_end),
+ map_start + map_size - shadow_end);
+ return shadow_start;
+}
+
+bool PremapShadowFailed() {
+ uptr shadow = reinterpret_cast<uptr>(&__asan_shadow);
+ uptr resolver = reinterpret_cast<uptr>(&__asan_premap_shadow);
+ // shadow == resolver is how Android KitKat and older handles ifunc.
+ // shadow == 0 just in case.
+ if (shadow == 0 || shadow == resolver)
+ return true;
+ return false;
+}
+} // namespace __asan
+
+extern "C" {
+decltype(__asan_shadow)* __asan_premap_shadow() {
+ // The resolver may be called multiple times. Map the shadow just once.
+ static uptr premapped_shadow = 0;
+ if (!premapped_shadow) premapped_shadow = __asan::PremapShadow();
+ return reinterpret_cast<decltype(__asan_shadow)*>(premapped_shadow);
+}
+
+// __asan_shadow is a "function" that has the same address as the first byte of
+// the shadow mapping.
+INTERFACE_ATTRIBUTE __attribute__((ifunc("__asan_premap_shadow"))) void
+__asan_shadow();
+}
+
+#endif // ASAN_PREMAP_SHADOW
diff --git a/lib/asan/asan_premap_shadow.h b/lib/asan/asan_premap_shadow.h
new file mode 100644
index 000000000000..41acbdbbb69f
--- /dev/null
+++ b/lib/asan/asan_premap_shadow.h
@@ -0,0 +1,30 @@
+//===-- asan_mapping.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Premap shadow range with an ifunc resolver.
+//===----------------------------------------------------------------------===//
+
+
+#ifndef ASAN_PREMAP_SHADOW_H
+#define ASAN_PREMAP_SHADOW_H
+
+#if ASAN_PREMAP_SHADOW
+namespace __asan {
+// Conservative upper limit.
+uptr PremapShadowSize();
+bool PremapShadowFailed();
+}
+#endif
+
+extern "C" INTERFACE_ATTRIBUTE void __asan_shadow();
+extern "C" decltype(__asan_shadow)* __asan_premap_shadow();
+
+#endif // ASAN_PREMAP_SHADOW_H
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index 2e477f258b8d..e3bc02994efd 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -60,9 +60,8 @@ void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
bool in_shadow, const char *after) {
Decorator d;
str->append("%s%s%x%x%s%s", before,
- in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
- byte >> 4, byte & 15,
- in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
+ in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4,
+ byte & 15, d.Default(), after);
}
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
@@ -123,53 +122,15 @@ bool ParseFrameDescription(const char *frame_descr,
// immediately after printing error report.
class ScopedInErrorReport {
public:
- explicit ScopedInErrorReport(bool fatal = false) {
- halt_on_error_ = fatal || flags()->halt_on_error;
-
- if (lock_.TryLock()) {
- StartReporting();
- return;
- }
-
- // ASan found two bugs in different threads simultaneously.
-
- u32 current_tid = GetCurrentTidOrInvalid();
- if (reporting_thread_tid_ == current_tid ||
- reporting_thread_tid_ == kInvalidTid) {
- // This is either asynch signal or nested error during error reporting.
- // Fail simple to avoid deadlocks in Report().
-
- // Can't use Report() here because of potential deadlocks
- // in nested signal handlers.
- const char msg[] = "AddressSanitizer: nested bug in the same thread, "
- "aborting.\n";
- WriteToFile(kStderrFd, msg, sizeof(msg));
-
- internal__exit(common_flags()->exitcode);
- }
-
- if (halt_on_error_) {
- // Do not print more than one report, otherwise they will mix up.
- // Error reporting functions shouldn't return at this situation, as
- // they are effectively no-returns.
-
- Report("AddressSanitizer: while reporting a bug found another one. "
- "Ignoring.\n");
-
- // Sleep long enough to make sure that the thread which started
- // to print an error report will finish doing it.
- SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
-
- // If we're still not dead for some reason, use raw _exit() instead of
- // Die() to bypass any additional checks.
- internal__exit(common_flags()->exitcode);
- } else {
- // The other thread will eventually finish reporting
- // so it's safe to wait
- lock_.Lock();
- }
-
- StartReporting();
+ explicit ScopedInErrorReport(bool fatal = false)
+ : halt_on_error_(fatal || flags()->halt_on_error) {
+ // Make sure the registry and sanitizer report mutexes are locked while
+ // we're printing an error report.
+ // We can lock them only here to avoid self-deadlock in case of
+ // recursive reports.
+ asanThreadRegistry().Lock();
+ Printf(
+ "=================================================================\n");
}
~ScopedInErrorReport() {
@@ -217,9 +178,6 @@ class ScopedInErrorReport {
if (!halt_on_error_)
internal_memset(&current_error_, 0, sizeof(current_error_));
- CommonSanitizerReportMutex.Unlock();
- reporting_thread_tid_ = kInvalidTid;
- lock_.Unlock();
if (halt_on_error_) {
Report("ABORTING\n");
Die();
@@ -237,39 +195,18 @@ class ScopedInErrorReport {
}
private:
- void StartReporting() {
- // Make sure the registry and sanitizer report mutexes are locked while
- // we're printing an error report.
- // We can lock them only here to avoid self-deadlock in case of
- // recursive reports.
- asanThreadRegistry().Lock();
- CommonSanitizerReportMutex.Lock();
- reporting_thread_tid_ = GetCurrentTidOrInvalid();
- Printf("===================================================="
- "=============\n");
- }
-
- static StaticSpinMutex lock_;
- static u32 reporting_thread_tid_;
+ ScopedErrorReportLock error_report_lock_;
// Error currently being reported. This enables the destructor to interact
// with the debugger and point it to an error description.
static ErrorDescription current_error_;
bool halt_on_error_;
};
-StaticSpinMutex ScopedInErrorReport::lock_;
-u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid;
ErrorDescription ScopedInErrorReport::current_error_;
-void ReportStackOverflow(const SignalContext &sig) {
+void ReportDeadlySignal(const SignalContext &sig) {
ScopedInErrorReport in_report(/*fatal*/ true);
- ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig);
- in_report.ReportError(error);
-}
-
-void ReportDeadlySignal(int signo, const SignalContext &sig) {
- ScopedInErrorReport in_report(/*fatal*/ true);
- ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo);
+ ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig);
in_report.ReportError(error);
}
@@ -279,11 +216,12 @@ void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
in_report.ReportError(error);
}
-void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
+ uptr delete_alignment,
BufferedStackTrace *free_stack) {
ScopedInErrorReport in_report;
- ErrorNewDeleteSizeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
- delete_size);
+ ErrorNewDeleteTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
+ delete_size, delete_alignment);
in_report.ReportError(error);
}
@@ -360,17 +298,58 @@ static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp,
in_report.ReportError(error);
}
+static bool IsInvalidPointerPair(uptr a1, uptr a2) {
+ if (a1 == a2)
+ return false;
+
+ // 256B in shadow memory can be iterated quite fast
+ static const uptr kMaxOffset = 2048;
+
+ uptr left = a1 < a2 ? a1 : a2;
+ uptr right = a1 < a2 ? a2 : a1;
+ uptr offset = right - left;
+ if (offset <= kMaxOffset)
+ return __asan_region_is_poisoned(left, offset);
+
+ AsanThread *t = GetCurrentThread();
+
+ // check whether left is a stack memory pointer
+ if (uptr shadow_offset1 = t->GetStackVariableShadowStart(left)) {
+ uptr shadow_offset2 = t->GetStackVariableShadowStart(right);
+ return shadow_offset2 == 0 || shadow_offset1 != shadow_offset2;
+ }
+
+ // check whether left is a heap memory address
+ HeapAddressDescription hdesc1, hdesc2;
+ if (GetHeapAddressInformation(left, 0, &hdesc1) &&
+ hdesc1.chunk_access.access_type == kAccessTypeInside)
+ return !GetHeapAddressInformation(right, 0, &hdesc2) ||
+ hdesc2.chunk_access.access_type != kAccessTypeInside ||
+ hdesc1.chunk_access.chunk_begin != hdesc2.chunk_access.chunk_begin;
+
+ // check whether left is an address of a global variable
+ GlobalAddressDescription gdesc1, gdesc2;
+ if (GetGlobalAddressInformation(left, 0, &gdesc1))
+ return !GetGlobalAddressInformation(right - 1, 0, &gdesc2) ||
+ !gdesc1.PointsInsideTheSameVariable(gdesc2);
+
+ if (t->GetStackVariableShadowStart(right) ||
+ GetHeapAddressInformation(right, 0, &hdesc2) ||
+ GetGlobalAddressInformation(right - 1, 0, &gdesc2))
+ return true;
+
+ // At this point we know nothing about both a1 and a2 addresses.
+ return false;
+}
+
static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
if (!flags()->detect_invalid_pointer_pairs) return;
uptr a1 = reinterpret_cast<uptr>(p1);
uptr a2 = reinterpret_cast<uptr>(p2);
- AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
- AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
- bool valid1 = chunk1.IsAllocated();
- bool valid2 = chunk2.IsAllocated();
- if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) {
+
+ if (IsInvalidPointerPair(a1, a2)) {
GET_CALLER_PC_BP_SP;
- return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
+ ReportInvalidPointerPair(pc, bp, sp, a1, a2);
}
}
// ----------------------- Mac-specific reports ----------------- {{{1
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index 5a3533a319af..f2cdad47ee81 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -46,9 +46,9 @@ bool ParseFrameDescription(const char *frame_descr,
// Different kinds of error reports.
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
uptr access_size, u32 exp, bool fatal);
-void ReportStackOverflow(const SignalContext &sig);
-void ReportDeadlySignal(int signo, const SignalContext &sig);
-void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+void ReportDeadlySignal(const SignalContext &sig);
+void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
+ uptr delete_alignment,
BufferedStackTrace *free_stack);
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 5ae3568ae04a..21fd0e240708 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -84,26 +84,6 @@ void ShowStatsAndAbort() {
Die();
}
-// ---------------------- mmap -------------------- {{{1
-// Reserve memory range [beg, end].
-// We need to use inclusive range because end+1 may not be representable.
-void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
- CHECK_EQ((beg % GetMmapGranularity()), 0);
- CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
- uptr size = end - beg + 1;
- DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
- void *res = MmapFixedNoReserve(beg, size, name);
- if (res != (void*)beg) {
- Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
- "Perhaps you're using ulimit -v\n", size);
- Abort();
- }
- if (common_flags()->no_huge_pages_for_shadow)
- NoHugePagesInRegion(beg, size);
- if (common_flags()->use_madv_dontdump)
- DontDumpShadowMemory(beg, size);
-}
-
// --------------- LowLevelAllocateCallbac ---------- {{{1
static void OnLowLevelAllocate(uptr ptr, uptr size) {
PoisonShadow(ptr, size, kAsanInternalHeapMagic);
@@ -327,7 +307,7 @@ static void asan_atexit() {
static void InitializeHighMemEnd() {
#if !ASAN_FIXED_MAPPING
- kHighMemEnd = GetMaxVirtualAddress();
+ kHighMemEnd = GetMaxUserVirtualAddress();
// Increase kHighMemEnd to make sure it's properly
// aligned together with kHighMemBeg:
kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;
@@ -335,46 +315,7 @@ static void InitializeHighMemEnd() {
CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
}
-static void ProtectGap(uptr addr, uptr size) {
- if (!flags()->protect_shadow_gap) {
- // The shadow gap is unprotected, so there is a chance that someone
- // is actually using this memory. Which means it needs a shadow...
- uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
- uptr GapShadowEnd =
- RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
- if (Verbosity())
- Printf("protect_shadow_gap=0:"
- " not protecting shadow gap, allocating gap's shadow\n"
- "|| `[%p, %p]` || ShadowGap's shadow ||\n", GapShadowBeg,
- GapShadowEnd);
- ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
- "unprotected gap shadow");
- return;
- }
- void *res = MmapFixedNoAccess(addr, size, "shadow gap");
- if (addr == (uptr)res)
- return;
- // A few pages at the start of the address space can not be protected.
- // But we really want to protect as much as possible, to prevent this memory
- // being returned as a result of a non-FIXED mmap().
- if (addr == kZeroBaseShadowStart) {
- uptr step = GetMmapGranularity();
- while (size > step && addr < kZeroBaseMaxShadowStart) {
- addr += step;
- size -= step;
- void *res = MmapFixedNoAccess(addr, size, "shadow gap");
- if (addr == (uptr)res)
- return;
- }
- }
-
- Report("ERROR: Failed to protect the shadow gap. "
- "ASan cannot proceed correctly. ABORTING.\n");
- DumpProcessMap();
- Die();
-}
-
-static void PrintAddressSpaceLayout() {
+void PrintAddressSpaceLayout() {
Printf("|| `[%p, %p]` || HighMem ||\n",
(void*)kHighMemBeg, (void*)kHighMemEnd);
Printf("|| `[%p, %p]` || HighShadow ||\n",
@@ -426,71 +367,6 @@ static void PrintAddressSpaceLayout() {
kHighShadowBeg > kMidMemEnd);
}
-static void InitializeShadowMemory() {
- // Set the shadow memory address to uninitialized.
- __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
-
- uptr shadow_start = kLowShadowBeg;
- // Detect if a dynamic shadow address must used and find a available location
- // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
- // expands to |__asan_shadow_memory_dynamic_address| which is
- // |kDefaultShadowSentinel|.
- if (shadow_start == kDefaultShadowSentinel) {
- __asan_shadow_memory_dynamic_address = 0;
- CHECK_EQ(0, kLowShadowBeg);
- shadow_start = FindDynamicShadowStart();
- }
- // Update the shadow memory address (potentially) used by instrumentation.
- __asan_shadow_memory_dynamic_address = shadow_start;
-
- if (kLowShadowBeg)
- shadow_start -= GetMmapGranularity();
- bool full_shadow_is_available =
- MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
-
-#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
- !ASAN_FIXED_MAPPING
- if (!full_shadow_is_available) {
- kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
- kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
- }
-#endif
-
- if (Verbosity()) PrintAddressSpaceLayout();
-
- if (full_shadow_is_available) {
- // mmap the low shadow plus at least one page at the left.
- if (kLowShadowBeg)
- ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
- // mmap the high shadow.
- ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
- // protect the gap.
- ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
- CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
- } else if (kMidMemBeg &&
- MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
- MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
- CHECK(kLowShadowBeg != kLowShadowEnd);
- // mmap the low shadow plus at least one page at the left.
- ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
- // mmap the mid shadow.
- ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
- // mmap the high shadow.
- ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
- // protect the gaps.
- ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
- ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
- ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
- } else {
- Report("Shadow memory range interleaves with an existing memory mapping. "
- "ASan cannot proceed correctly. ABORTING.\n");
- Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
- shadow_start, kHighShadowEnd);
- DumpProcessMap();
- Die();
- }
-}
-
static void AsanInitInternal() {
if (LIKELY(asan_inited)) return;
SanitizerToolName = "AddressSanitizer";
@@ -531,6 +407,7 @@ static void AsanInitInternal() {
MaybeReexec();
// Setup internal allocator callback.
+ SetLowLevelAllocateMinAlignment(SHADOW_GRANULARITY);
SetLowLevelAllocateCallback(OnLowLevelAllocate);
InitializeAsanInterceptors();
@@ -575,20 +452,18 @@ static void AsanInitInternal() {
InitTlsSize();
// Create main thread.
- AsanThread *main_thread = AsanThread::Create(
- /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
- /* stack */ nullptr, /* detached */ true);
+ AsanThread *main_thread = CreateMainThread();
CHECK_EQ(0, main_thread->tid());
- SetCurrentThread(main_thread);
- main_thread->ThreadStart(internal_getpid(),
- /* signal_thread_is_registered */ nullptr);
force_interface_symbols(); // no-op.
SanitizerInitializeUnwinder();
if (CAN_SANITIZE_LEAKS) {
__lsan::InitCommonLsan();
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
- Atexit(__lsan::DoLeakCheck);
+ if (flags()->halt_on_error)
+ Atexit(__lsan::DoLeakCheck);
+ else
+ Atexit(__lsan::DoRecoverableLeakCheckVoid);
}
}
@@ -608,6 +483,11 @@ static void AsanInitInternal() {
}
VReport(1, "AddressSanitizer Init done\n");
+
+ if (flags()->sleep_after_init) {
+ Report("Sleeping for %d second(s)\n", flags()->sleep_after_init);
+ SleepForSeconds(flags()->sleep_after_init);
+ }
}
// Initialize as requested from some part of ASan runtime library (interceptors,
@@ -647,6 +527,7 @@ void NOINLINE __asan_handle_no_return() {
top = curr_thread->stack_top();
bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1);
} else {
+ CHECK(!SANITIZER_FUCHSIA);
// If we haven't seen this thread, try asking the OS for stack bounds.
uptr tls_addr, tls_size, stack_size;
GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr,
diff --git a/lib/asan/asan_scariness_score.h b/lib/asan/asan_scariness_score.h
index 7f1571416fd5..7f095dd29f29 100644
--- a/lib/asan/asan_scariness_score.h
+++ b/lib/asan/asan_scariness_score.h
@@ -47,7 +47,7 @@ struct ScarinessScoreBase {
};
int GetScore() const { return score; }
const char *GetDescription() const { return descr; }
- void Print() {
+ void Print() const {
if (score && flags()->print_scariness)
Printf("SCARINESS: %d (%s)\n", score, descr);
}
diff --git a/lib/asan/asan_shadow_setup.cc b/lib/asan/asan_shadow_setup.cc
new file mode 100644
index 000000000000..b3cf0b5c1ce2
--- /dev/null
+++ b/lib/asan/asan_shadow_setup.cc
@@ -0,0 +1,165 @@
+//===-- asan_shadow_setup.cc ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Set up the shadow memory.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+// asan_fuchsia.cc has its own InitializeShadowMemory implementation.
+#if !SANITIZER_FUCHSIA
+
+#include "asan_internal.h"
+#include "asan_mapping.h"
+
+namespace __asan {
+
+// ---------------------- mmap -------------------- {{{1
+// Reserve memory range [beg, end].
+// We need to use inclusive range because end+1 may not be representable.
+void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
+ CHECK_EQ((beg % GetMmapGranularity()), 0);
+ CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
+ uptr size = end - beg + 1;
+ DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
+ void *res = MmapFixedNoReserve(beg, size, name);
+ if (res != (void *)beg) {
+ Report(
+ "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
+ "Perhaps you're using ulimit -v\n",
+ size);
+ Abort();
+ }
+ if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
+ if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
+}
+
+static void ProtectGap(uptr addr, uptr size) {
+ if (!flags()->protect_shadow_gap) {
+ // The shadow gap is unprotected, so there is a chance that someone
+ // is actually using this memory. Which means it needs a shadow...
+ uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
+ uptr GapShadowEnd =
+ RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
+ if (Verbosity())
+ Printf(
+ "protect_shadow_gap=0:"
+ " not protecting shadow gap, allocating gap's shadow\n"
+ "|| `[%p, %p]` || ShadowGap's shadow ||\n",
+ GapShadowBeg, GapShadowEnd);
+ ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
+ "unprotected gap shadow");
+ return;
+ }
+ void *res = MmapFixedNoAccess(addr, size, "shadow gap");
+ if (addr == (uptr)res) return;
+ // A few pages at the start of the address space can not be protected.
+ // But we really want to protect as much as possible, to prevent this memory
+ // being returned as a result of a non-FIXED mmap().
+ if (addr == kZeroBaseShadowStart) {
+ uptr step = GetMmapGranularity();
+ while (size > step && addr < kZeroBaseMaxShadowStart) {
+ addr += step;
+ size -= step;
+ void *res = MmapFixedNoAccess(addr, size, "shadow gap");
+ if (addr == (uptr)res) return;
+ }
+ }
+
+ Report(
+ "ERROR: Failed to protect the shadow gap. "
+ "ASan cannot proceed correctly. ABORTING.\n");
+ DumpProcessMap();
+ Die();
+}
+
+static void MaybeReportLinuxPIEBug() {
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__))
+ Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
+ Report(
+ "See https://github.com/google/sanitizers/issues/856 for possible "
+ "workarounds.\n");
+#endif
+}
+
+void InitializeShadowMemory() {
+ // Set the shadow memory address to uninitialized.
+ __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
+
+ uptr shadow_start = kLowShadowBeg;
+ // Detect if a dynamic shadow address must used and find a available location
+ // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
+ // expands to |__asan_shadow_memory_dynamic_address| which is
+ // |kDefaultShadowSentinel|.
+ bool full_shadow_is_available = false;
+ if (shadow_start == kDefaultShadowSentinel) {
+ __asan_shadow_memory_dynamic_address = 0;
+ CHECK_EQ(0, kLowShadowBeg);
+ shadow_start = FindDynamicShadowStart();
+ if (SANITIZER_LINUX) full_shadow_is_available = true;
+ }
+ // Update the shadow memory address (potentially) used by instrumentation.
+ __asan_shadow_memory_dynamic_address = shadow_start;
+
+ if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
+
+ if (!full_shadow_is_available)
+ full_shadow_is_available =
+ MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
+
+#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
+ !ASAN_FIXED_MAPPING
+ if (!full_shadow_is_available) {
+ kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
+ kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
+ }
+#endif
+
+ if (Verbosity()) PrintAddressSpaceLayout();
+
+ if (full_shadow_is_available) {
+ // mmap the low shadow plus at least one page at the left.
+ if (kLowShadowBeg)
+ ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
+ // mmap the high shadow.
+ ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
+ // protect the gap.
+ ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+ CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
+ } else if (kMidMemBeg &&
+ MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
+ MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
+ CHECK(kLowShadowBeg != kLowShadowEnd);
+ // mmap the low shadow plus at least one page at the left.
+ ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
+ // mmap the mid shadow.
+ ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
+ // mmap the high shadow.
+ ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
+ // protect the gaps.
+ ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+ ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
+ ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
+ } else {
+ Report(
+ "Shadow memory range interleaves with an existing memory mapping. "
+ "ASan cannot proceed correctly. ABORTING.\n");
+ Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
+ shadow_start, kHighShadowEnd);
+ MaybeReportLinuxPIEBug();
+ DumpProcessMap();
+ Die();
+ }
+}
+
+} // namespace __asan
+
+#endif // !SANITIZER_FUCHSIA
diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index cc95e0f30a33..8e9df888d798 100644
--- a/lib/asan/asan_stack.h
+++ b/lib/asan/asan_stack.h
@@ -31,9 +31,8 @@ u32 GetMallocContextSize();
// The pc will be in the position 0 of the resulting stack trace.
// The bp may refer to the current frame or to the caller's frame.
ALWAYS_INLINE
-void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
- uptr pc, uptr bp, void *context,
- bool fast) {
+void GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, uptr bp,
+ void *context, bool fast) {
#if SANITIZER_WINDOWS
stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
#else
@@ -41,10 +40,6 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
stack->size = 0;
if (LIKELY(asan_inited)) {
if ((t = GetCurrentThread()) && !t->isUnwinding()) {
- // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
- // yields the call stack of the signal's handler and not of the code
- // that raised the signal (as it does on Linux).
- if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
uptr stack_top = t->stack_top();
uptr stack_bottom = t->stack_bottom();
ScopedUnwinding unwind_scope(t);
@@ -66,32 +61,29 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
// as early as possible (in functions exposed to the user), as we generally
// don't want stack trace to contain functions from ASan internals.
-#define GET_STACK_TRACE(max_size, fast) \
- BufferedStackTrace stack; \
- if (max_size <= 2) { \
- stack.size = max_size; \
- if (max_size > 0) { \
- stack.top_frame_bp = GET_CURRENT_FRAME(); \
- stack.trace_buffer[0] = StackTrace::GetCurrentPc(); \
- if (max_size > 1) \
- stack.trace_buffer[1] = GET_CALLER_PC(); \
- } \
- } else { \
- GetStackTraceWithPcBpAndContext(&stack, max_size, \
- StackTrace::GetCurrentPc(), \
- GET_CURRENT_FRAME(), 0, fast); \
+#define GET_STACK_TRACE(max_size, fast) \
+ BufferedStackTrace stack; \
+ if (max_size <= 2) { \
+ stack.size = max_size; \
+ if (max_size > 0) { \
+ stack.top_frame_bp = GET_CURRENT_FRAME(); \
+ stack.trace_buffer[0] = StackTrace::GetCurrentPc(); \
+ if (max_size > 1) stack.trace_buffer[1] = GET_CALLER_PC(); \
+ } \
+ } else { \
+ GetStackTrace(&stack, max_size, StackTrace::GetCurrentPc(), \
+ GET_CURRENT_FRAME(), 0, fast); \
}
-#define GET_STACK_TRACE_FATAL(pc, bp) \
- BufferedStackTrace stack; \
- GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0, \
- common_flags()->fast_unwind_on_fatal)
+#define GET_STACK_TRACE_FATAL(pc, bp) \
+ BufferedStackTrace stack; \
+ GetStackTrace(&stack, kStackTraceMax, pc, bp, 0, \
+ common_flags()->fast_unwind_on_fatal)
-#define GET_STACK_TRACE_SIGNAL(sig) \
- BufferedStackTrace stack; \
- GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, \
- (sig).pc, (sig).bp, (sig).context, \
- common_flags()->fast_unwind_on_fatal)
+#define GET_STACK_TRACE_SIGNAL(sig) \
+ BufferedStackTrace stack; \
+ GetStackTrace(&stack, kStackTraceMax, (sig).pc, (sig).bp, (sig).context, \
+ common_flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_FATAL_HERE \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index b1a0d9a3b37f..ad81512dff08 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -27,11 +27,6 @@ namespace __asan {
// AsanThreadContext implementation.
-struct CreateThreadContextArgs {
- AsanThread *thread;
- StackTrace *stack;
-};
-
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
if (args->stack)
@@ -88,7 +83,7 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
thread->start_routine_ = start_routine;
thread->arg_ = arg;
- CreateThreadContextArgs args = { thread, stack };
+ AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
parent_tid, &args);
@@ -223,12 +218,12 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
return nullptr;
}
-void AsanThread::Init() {
+void AsanThread::Init(const InitOptions *options) {
next_stack_top_ = next_stack_bottom_ = 0;
atomic_store(&stack_switching_, false, memory_order_release);
fake_stack_ = nullptr; // Will be initialized lazily if needed.
CHECK_EQ(this->stack_size(), 0U);
- SetThreadStackAndTls();
+ SetThreadStackAndTls(options);
CHECK_GT(this->stack_size(), 0U);
CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1));
@@ -239,6 +234,10 @@ void AsanThread::Init() {
&local);
}
+// Fuchsia doesn't use ThreadStart.
+// asan_fuchsia.c defines CreateMainThread and SetThreadStackAndTls.
+#if !SANITIZER_FUCHSIA
+
thread_return_t AsanThread::ThreadStart(
tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
Init();
@@ -270,7 +269,21 @@ thread_return_t AsanThread::ThreadStart(
return res;
}
-void AsanThread::SetThreadStackAndTls() {
+AsanThread *CreateMainThread() {
+ AsanThread *main_thread = AsanThread::Create(
+ /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
+ /* stack */ nullptr, /* detached */ true);
+ SetCurrentThread(main_thread);
+ main_thread->ThreadStart(internal_getpid(),
+ /* signal_thread_is_registered */ nullptr);
+ return main_thread;
+}
+
+// This implementation doesn't use the argument, which is just passed down
+// from the caller of Init (which see, above). It's only there to support
+// OS-specific implementations that need more information passed through.
+void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
+ DCHECK_EQ(options, nullptr);
uptr tls_size = 0;
uptr stack_size = 0;
GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
@@ -283,6 +296,8 @@ void AsanThread::SetThreadStackAndTls() {
CHECK(AddrIsInStack((uptr)&local));
}
+#endif // !SANITIZER_FUCHSIA
+
void AsanThread::ClearShadowForThreadStackAndTLS() {
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
if (tls_begin_ != tls_end_)
@@ -302,7 +317,7 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
access->frame_descr = (const char *)((uptr*)bottom)[1];
return true;
}
- uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
+ uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr.
uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
u8 *shadow_bottom = (u8*)MemToShadow(bottom);
@@ -331,6 +346,29 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
return true;
}
+uptr AsanThread::GetStackVariableShadowStart(uptr addr) {
+ uptr bottom = 0;
+ if (AddrIsInStack(addr)) {
+ bottom = stack_bottom();
+ } else if (has_fake_stack()) {
+ bottom = fake_stack()->AddrIsInFakeStack(addr);
+ CHECK(bottom);
+ } else
+ return 0;
+
+ uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr.
+ u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
+ u8 *shadow_bottom = (u8*)MemToShadow(bottom);
+
+ while (shadow_ptr >= shadow_bottom &&
+ (*shadow_ptr != kAsanStackLeftRedzoneMagic &&
+ *shadow_ptr != kAsanStackMidRedzoneMagic &&
+ *shadow_ptr != kAsanStackRightRedzoneMagic))
+ shadow_ptr--;
+
+ return (uptr)shadow_ptr + 1;
+}
+
bool AsanThread::AddrIsInStack(uptr addr) {
const auto bounds = GetStackBounds();
return addr >= bounds.bottom && addr < bounds.top;
diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index 424f9e68dfea..66091921101f 100644
--- a/lib/asan/asan_thread.h
+++ b/lib/asan/asan_thread.h
@@ -49,6 +49,11 @@ class AsanThreadContext : public ThreadContextBase {
void OnCreated(void *arg) override;
void OnFinished() override;
+
+ struct CreateThreadContextArgs {
+ AsanThread *thread;
+ StackTrace *stack;
+ };
};
// AsanThreadContext objects are never freed, so we need many of them.
@@ -62,7 +67,9 @@ class AsanThread {
static void TSDDtor(void *tsd);
void Destroy();
- void Init(); // Should be called from the thread itself.
+ struct InitOptions;
+ void Init(const InitOptions *options = nullptr);
+
thread_return_t ThreadStart(tid_t os_id,
atomic_uintptr_t *signal_thread_is_registered);
@@ -83,6 +90,9 @@ class AsanThread {
};
bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
+ // Returns a pointer to the start of the stack variable's shadow memory.
+ uptr GetStackVariableShadowStart(uptr addr);
+
bool AddrIsInStack(uptr addr);
void DeleteFakeStack(int tid) {
@@ -118,17 +128,15 @@ class AsanThread {
bool isUnwinding() const { return unwinding_; }
void setUnwinding(bool b) { unwinding_ = b; }
- // True if we are in a deadly signal handler.
- bool isInDeadlySignal() const { return in_deadly_signal_; }
- void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
-
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; }
private:
// NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
- void SetThreadStackAndTls();
+
+ void SetThreadStackAndTls(const InitOptions *options);
+
void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack();
@@ -158,7 +166,6 @@ class AsanThread {
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
bool unwinding_;
- bool in_deadly_signal_;
};
// ScopedUnwinding is a scope for stacktracing member of a context
@@ -173,20 +180,6 @@ class ScopedUnwinding {
AsanThread *thread;
};
-// ScopedDeadlySignal is a scope for handling deadly signals.
-class ScopedDeadlySignal {
- public:
- explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
- if (thread) thread->setInDeadlySignal(true);
- }
- ~ScopedDeadlySignal() {
- if (thread) thread->setInDeadlySignal(false);
- }
-
- private:
- AsanThread *thread;
-};
-
// Returns a single instance of registry.
ThreadRegistry &asanThreadRegistry();
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 8a839d913f95..68eedd1863bc 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -57,8 +57,8 @@ long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) {
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
- SignalContext sig = SignalContext::Create(exception_record, context);
- ReportDeadlySignal(exception_record->ExceptionCode, sig);
+ SignalContext sig(exception_record, context);
+ ReportDeadlySignal(sig);
UNREACHABLE("returned from reporting deadly signal");
}
diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup
index 5a4f7c47cc21..92a109727267 100755
--- a/lib/asan/scripts/asan_device_setup
+++ b/lib/asan/scripts/asan_device_setup
@@ -95,7 +95,7 @@ function get_device_arch { # OUT OUT64
local _ARCH=
local _ARCH64=
if [[ $_ABI == x86* ]]; then
- _ARCH=i686
+ _ARCH=i386
elif [[ $_ABI == armeabi* ]]; then
_ARCH=arm
elif [[ $_ABI == arm64-v8a* ]]; then
@@ -181,6 +181,17 @@ if [[ -n $ARCH64 ]]; then
ASAN_RT64="libclang_rt.asan-$ARCH64-android.so"
fi
+RELEASE=$(adb_shell getprop ro.build.version.release)
+PRE_L=0
+if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
+ PRE_L=1
+fi
+ANDROID_O=0
+if echo "$RELEASE" | grep '^8\.0\.' >&/dev/null; then
+ # 8.0.x is for Android O
+ ANDROID_O=1
+fi
+
if [[ x$revert == xyes ]]; then
echo '>> Uninstalling ASan'
@@ -202,6 +213,10 @@ if [[ x$revert == xyes ]]; then
adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
fi
+ if [[ ANDROID_O -eq 1 ]]; then
+ adb_shell mv /system/etc/ld.config.txt.saved /system/etc/ld.config.txt
+ fi
+
echo '>> Restarting shell'
adb_shell stop
adb_shell start
@@ -251,12 +266,6 @@ TMPDIROLD="$TMPDIRBASE/old"
TMPDIR="$TMPDIRBASE/new"
mkdir "$TMPDIROLD"
-RELEASE=$(adb_shell getprop ro.build.version.release)
-PRE_L=0
-if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
- PRE_L=1
-fi
-
if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then
@@ -410,15 +419,18 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
install "$TMPDIR/asanwrapper" /system/bin 755
install "$TMPDIR/asanwrapper64" /system/bin 755
- adb_shell ln -sf $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
- adb_shell ln -sf $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK
+ adb_shell rm -f /system/lib/$ASAN_RT_SYMLINK
+ adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
+ adb_shell rm -f /system/lib64/$ASAN_RT_SYMLINK
+ adb_shell ln -s $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK
else
install "$TMPDIR/$ASAN_RT" /system/lib 644
install "$TMPDIR/app_process32" /system/bin 755 $CTX
install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX
install "$TMPDIR/asanwrapper" /system/bin 755 $CTX
- adb_shell ln -sf $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
+ adb_shell rm -f /system/lib/$ASAN_RT_SYMLINK
+ adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
adb_shell rm /system/bin/app_process
adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process
@@ -427,6 +439,11 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
adb_shell cp /system/bin/sh /system/bin/sh-from-zygote
adb_shell chcon $CTX /system/bin/sh-from-zygote
+ if [[ ANDROID_O -eq 1 ]]; then
+ # For Android O, the linker namespace is temporarily disabled.
+ adb_shell mv /system/etc/ld.config.txt /system/etc/ld.config.txt.saved
+ fi
+
if [ $ENFORCING == 1 ]; then
adb_shell setenforce 1
fi
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index 1a56e44127c1..cd5d89ba2219 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -280,7 +280,7 @@ def BreakpadSymbolizerFactory(binary):
def SystemSymbolizerFactory(system, addr, binary, arch):
if system == 'Darwin':
return DarwinSymbolizer(addr, binary, arch)
- elif system == 'Linux' or system == 'FreeBSD':
+ elif system in ['Linux', 'FreeBSD', 'NetBSD']:
return Addr2LineSymbolizer(binary)
@@ -370,7 +370,7 @@ class SymbolizationLoop(object):
self.binary_name_filter = binary_name_filter
self.dsym_hint_producer = dsym_hint_producer
self.system = os.uname()[0]
- if self.system not in ['Linux', 'Darwin', 'FreeBSD']:
+ if self.system not in ['Linux', 'Darwin', 'FreeBSD', 'NetBSD']:
raise Exception('Unknown system')
self.llvm_symbolizers = {}
self.last_llvm_symbolizer = None
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index 8089d51efe68..67a8fafaba3c 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -23,6 +23,7 @@ set(ASAN_UNITTEST_HEADERS
set(ASAN_UNITTEST_COMMON_CFLAGS
${COMPILER_RT_UNITTEST_CFLAGS}
${COMPILER_RT_GTEST_CFLAGS}
+ ${COMPILER_RT_ASAN_SHADOW_SCALE_LLVM_FLAG}
-I${COMPILER_RT_SOURCE_DIR}/include
-I${COMPILER_RT_SOURCE_DIR}/lib
-I${COMPILER_RT_SOURCE_DIR}/lib/asan
@@ -52,6 +53,7 @@ list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS -g)
# Use -D instead of definitions to please custom compile command.
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
+ ${COMPILER_RT_ASAN_SHADOW_SCALE_FLAG}
-DASAN_HAS_BLACKLIST=1
-DASAN_HAS_EXCEPTIONS=1
-DASAN_UAR=0)
@@ -125,57 +127,6 @@ append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_UNITTEST_NOINST_LIBS)
# NDK r10 requires -latomic almost always.
append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS)
-# Compile source for the given architecture, using compiler
-# options in ${ARGN}, and add it to the object list.
-macro(asan_compile obj_list source arch kind)
- get_filename_component(basename ${source} NAME)
- if(CMAKE_CONFIGURATION_TYPES)
- set(output_obj "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${kind}.o")
- else()
- set(output_obj "${obj_list}.${basename}.${arch}${kind}.o")
- endif()
- get_target_flags_for_arch(${arch} TARGET_CFLAGS)
- set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE})
- if(NOT COMPILER_RT_STANDALONE_BUILD)
- list(APPEND COMPILE_DEPS gtest asan)
- endif()
- clang_compile(${output_obj} ${source}
- CFLAGS ${ARGN} ${TARGET_CFLAGS}
- DEPS ${COMPILE_DEPS})
- list(APPEND ${obj_list} ${output_obj})
-endmacro()
-
-# Link ASan unit test for a given architecture from a set
-# of objects in with given linker flags.
-macro(add_asan_test test_suite test_name arch kind)
- cmake_parse_arguments(TEST "WITH_TEST_RUNTIME" "" "OBJECTS;LINK_FLAGS;SUBDIR" ${ARGN})
- get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
- set(TEST_DEPS ${TEST_OBJECTS})
- if(NOT COMPILER_RT_STANDALONE_BUILD)
- list(APPEND TEST_DEPS asan)
- endif()
- if(TEST_WITH_TEST_RUNTIME)
- list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME})
- if(CMAKE_CONFIGURATION_TYPES)
- set(configuration_path "${CMAKE_CFG_INTDIR}/")
- else()
- set(configuration_path "")
- endif()
- if(NOT MSVC)
- set(asan_test_runtime_path ${configuration_path}lib${ASAN_TEST_RUNTIME}.a)
- else()
- set(asan_test_runtime_path ${configuration_path}${ASAN_TEST_RUNTIME}.lib)
- endif()
- list(APPEND TEST_OBJECTS ${asan_test_runtime_path})
- endif()
- add_compiler_rt_test(${test_suite} ${test_name}
- SUBDIR ${TEST_SUBDIR}
- OBJECTS ${TEST_OBJECTS}
- DEPS ${TEST_DEPS}
- LINK_FLAGS ${TEST_LINK_FLAGS}
- ${TARGET_LINK_FLAGS})
-endmacro()
-
# Main AddressSanitizer unit tests.
add_custom_target(AsanUnitTests)
set_target_properties(AsanUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
@@ -206,131 +157,118 @@ set(ASAN_INST_TEST_SOURCES
asan_str_test.cc
asan_test_main.cc)
if(APPLE)
- list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc)
+ list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc asan_mac_test_helpers.mm)
endif()
set(ASAN_BENCHMARKS_SOURCES
${COMPILER_RT_GTEST_SOURCE}
asan_benchmarks_test.cc)
-# Adds ASan unit tests and benchmarks for architecture.
-macro(add_asan_tests_for_arch_and_kind arch kind)
- # Instrumented tests.
- set(ASAN_INST_TEST_OBJECTS)
- foreach(src ${ASAN_INST_TEST_SOURCES})
- asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${kind}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
- endforeach()
- if (APPLE)
- # Add Mac-specific helper.
- asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${kind}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${ARGN})
- endif()
+function(add_asan_tests arch test_runtime)
+ cmake_parse_arguments(TEST "" "KIND" "CFLAGS" ${ARGN})
- if (MSVC)
- # With the MSVC CRT, the choice between static and dynamic CRT is made at
- # compile time with a macro. Simulate the effect of passing /MD to clang-cl.
- set(ASAN_INST_DYNAMIC_TEST_OBJECTS)
- foreach(src ${ASAN_INST_TEST_SOURCES})
- asan_compile(ASAN_INST_DYNAMIC_TEST_OBJECTS ${src} ${arch} ${kind}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL ${ARGN})
- endforeach()
- # Clang links the static CRT by default. Override that to use the dynamic
- # CRT.
- set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS
- ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}
- -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames)
- else()
- set(ASAN_INST_DYNAMIC_TEST_OBJECTS ${ASAN_INST_TEST_OBJECTS})
- endif()
+ # Closure to keep the values.
+ function(generate_asan_tests test_objects test_suite testname)
+ generate_compiler_rt_tests(${test_objects} ${test_suite} ${testname} ${arch}
+ COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE}
+ DEPS gtest asan
+ KIND ${TEST_KIND}
+ ${ARGN}
+ )
+ set("${test_objects}" "${${test_objects}}" PARENT_SCOPE)
+ endfunction()
- # Create the 'default' folder where ASAN tests are produced.
- if(CMAKE_CONFIGURATION_TYPES)
- foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
- file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${build_mode}")
- endforeach()
- else()
- file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default")
- endif()
+ set(ASAN_INST_TEST_OBJECTS)
+ generate_asan_tests(ASAN_INST_TEST_OBJECTS AsanUnitTests
+ "Asan-${arch}${TEST_KIND}-Test"
+ SUBDIR "default"
+ LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}
+ SOURCES ${ASAN_INST_TEST_SOURCES}
+ CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${TEST_CFLAGS})
- add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test"
- ${arch} ${kind} SUBDIR "default"
- OBJECTS ${ASAN_INST_TEST_OBJECTS}
- LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS})
if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME)
- # Create the 'dynamic' folder where ASAN tests are produced.
- if(CMAKE_CONFIGURATION_TYPES)
- foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
- file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${build_mode}")
- endforeach()
+ set(dynamic_test_name "Asan-${arch}${TEST_KIND}-Dynamic-Test")
+ if(MSVC)
+
+ # With the MSVC CRT, the choice between static and dynamic CRT is made at
+ # compile time with a macro. Simulate the effect of passing /MD to clang-cl.
+ set(ASAN_DYNAMIC_TEST_OBJECTS)
+ generate_asan_tests(ASAN_DYNAMIC_TEST_OBJECTS
+ AsanDynamicUnitTests "${dynamic_test_name}"
+ SUBDIR "dynamic"
+ CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL
+ SOURCES ${ASAN_INST_TEST_SOURCES}
+ LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}
+ -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames
+ )
else()
- file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic")
- endif()
- add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test"
- ${arch} ${kind} SUBDIR "dynamic"
- OBJECTS ${ASAN_INST_DYNAMIC_TEST_OBJECTS}
- LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS})
+ # Otherwise, reuse ASAN_INST_TEST_OBJECTS.
+ add_compiler_rt_test(AsanDynamicUnitTests "${dynamic_test_name}" "${arch}"
+ SUBDIR "dynamic"
+ OBJECTS ${ASAN_INST_TEST_OBJECTS}
+ DEPS asan ${ASAN_INST_TEST_OBJECTS}
+ LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}
+ )
+ endif()
endif()
- # Add static ASan runtime that will be linked with uninstrumented tests.
- set(ASAN_TEST_RUNTIME RTAsanTest.${arch}${kind})
- if(APPLE)
- set(ASAN_TEST_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTAsan_dynamic.osx>
- $<TARGET_OBJECTS:RTInterception.osx>
- $<TARGET_OBJECTS:RTSanitizerCommon.osx>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>
- $<TARGET_OBJECTS:RTLSanCommon.osx>
- $<TARGET_OBJECTS:RTUbsan.osx>)
- else()
- set(ASAN_TEST_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTAsan.${arch}>
- $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
- $<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- $<TARGET_OBJECTS:RTLSanCommon.${arch}>
- $<TARGET_OBJECTS:RTUbsan.${arch}>
- $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>)
- endif()
- add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
- set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
- ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- FOLDER "Compiler-RT Runtime tests")
# Uninstrumented tests.
set(ASAN_NOINST_TEST_OBJECTS)
- foreach(src ${ASAN_NOINST_TEST_SOURCES})
- asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch} ${kind}
- ${ASAN_UNITTEST_COMMON_CFLAGS} ${ARGN})
- endforeach()
- add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Noinst-Test"
- ${arch} ${kind} SUBDIR "default"
- OBJECTS ${ASAN_NOINST_TEST_OBJECTS}
- LINK_FLAGS ${ASAN_UNITTEST_NOINST_LINK_FLAGS}
- WITH_TEST_RUNTIME)
-
- # Benchmarks.
- set(ASAN_BENCHMARKS_OBJECTS)
- foreach(src ${ASAN_BENCHMARKS_SOURCES})
- asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch} ${kind}
- ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
- endforeach()
- add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Benchmark"
- ${arch} ${kind} SUBDIR "default"
- OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
- LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS})
-endmacro()
+ generate_asan_tests(ASAN_NOINST_TEST_OBJECTS
+ AsanUnitTests "Asan-${arch}${TEST_KIND}-Noinst-Test"
+ SUBDIR "default"
+ CFLAGS ${ASAN_UNITTEST_COMMON_CFLAGS}
+ LINK_FLAGS ${ASAN_UNITTEST_NOINST_LINK_FLAGS}
+ SOURCES ${ASAN_NOINST_TEST_SOURCES}
+ RUNTIME ${test_runtime})
+
+ set(ASAN_BENCHMARK_OBJECTS)
+ generate_asan_tests(ASAN_BENCHMARK_OBJECTS
+ AsanBenchmarks "Asan-${arch}${TEST_KIND}-Benchmark"
+ SUBDIR "default"
+ CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}
+ SOURCES ${ASAN_BENCHMARKS_SOURCES}
+ LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS})
+endfunction()
if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH})
if(APPLE)
darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)
endif()
+
foreach(arch ${ASAN_TEST_ARCH})
- add_asan_tests_for_arch_and_kind(${arch} "-inline")
- add_asan_tests_for_arch_and_kind(${arch} "-with-calls"
- -mllvm -asan-instrumentation-with-call-threshold=0)
+
+ # Add static ASan runtime that will be linked with uninstrumented tests.
+ set(ASAN_TEST_RUNTIME RTAsanTest.${arch})
+ if(APPLE)
+ set(ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan_dynamic.osx>
+ $<TARGET_OBJECTS:RTInterception.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommon.osx>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>
+ $<TARGET_OBJECTS:RTLSanCommon.osx>
+ $<TARGET_OBJECTS:RTUbsan.osx>)
+ else()
+ set(ASAN_TEST_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+ $<TARGET_OBJECTS:RTUbsan.${arch}>
+ $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>)
+ endif()
+ add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
+ set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ FOLDER "Compiler-RT Runtime tests")
+
+ add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-inline")
+ add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-calls"
+ CFLAGS -mllvm -asan-instrumentation-with-call-threshold=0)
endforeach()
endif()
diff --git a/lib/asan/tests/asan_asm_test.cc b/lib/asan/tests/asan_asm_test.cc
index 2bb37946bb4a..91f8aacd6eeb 100644
--- a/lib/asan/tests/asan_asm_test.cc
+++ b/lib/asan/tests/asan_asm_test.cc
@@ -12,7 +12,8 @@
//===----------------------------------------------------------------------===//
#include "asan_test_utils.h"
-#if defined(__linux__)
+#if defined(__linux__) && \
+ (!defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3)
// Assembly instrumentation is broken on x86 Android (x86 + PIC + shared runtime
// library). See https://github.com/google/sanitizers/issues/353
diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc
index 7d3e520d81a4..69c8fe6f4818 100644
--- a/lib/asan/tests/asan_interface_test.cc
+++ b/lib/asan/tests/asan_interface_test.cc
@@ -153,14 +153,15 @@ TEST(AddressSanitizerInterface, DeathCallbackTest) {
__asan_set_death_callback(NULL);
}
-static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
-
#define GOOD_ACCESS(ptr, offset) \
EXPECT_FALSE(__asan_address_is_poisoned(ptr + offset))
#define BAD_ACCESS(ptr, offset) \
EXPECT_TRUE(__asan_address_is_poisoned(ptr + offset))
+#if !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
+static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
+
TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
char *array = Ident((char*)malloc(120));
// poison array[40..80)
@@ -199,6 +200,7 @@ TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
BAD_ACCESS(array, 96);
free(array);
}
+#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
// Vector of capacity 20
@@ -219,6 +221,7 @@ TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
free(vec);
}
+#if !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
// Make sure that each aligned block of size "2^granularity" doesn't have
// "true" value before "false" value.
static void MakeShadowValid(bool *shadow, int length, int granularity) {
@@ -272,6 +275,7 @@ TEST(AddressSanitizerInterface, PoisoningStressTest) {
}
free(arr);
}
+#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
TEST(AddressSanitizerInterface, GlobalRedzones) {
GOOD_ACCESS(glob1, 1 - 1);
@@ -386,23 +390,6 @@ TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
free(array);
}
-#if !defined(_WIN32) // FIXME: This should really be a lit test.
-static void ErrorReportCallbackOneToZ(const char *report) {
- int report_len = strlen(report);
- ASSERT_EQ(6, write(2, "ABCDEF", 6));
- ASSERT_EQ(report_len, write(2, report, report_len));
- ASSERT_EQ(6, write(2, "ABCDEF", 6));
- _exit(1);
-}
-
-TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
- __asan_set_error_report_callback(ErrorReportCallbackOneToZ);
- EXPECT_DEATH(__asan_report_error((void *)GET_CALLER_PC(), 0, 0, 0, true, 1),
- ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
- __asan_set_error_report_callback(NULL);
-}
-#endif
-
TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
std::vector<char *> pointers;
std::vector<size_t> sizes;
@@ -423,3 +410,11 @@ TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
free(pointers[i]);
}
+TEST(AddressSanitizerInterface, HandleNoReturnTest) {
+ char array[40];
+ __asan_poison_memory_region(array, sizeof(array));
+ BAD_ACCESS(array, 20);
+ __asan_handle_no_return();
+ // It unpoisons the whole thread stack.
+ GOOD_ACCESS(array, 20);
+}
diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc
index 964f6da0297d..5cf4e05c81c8 100644
--- a/lib/asan/tests/asan_str_test.cc
+++ b/lib/asan/tests/asan_str_test.cc
@@ -95,6 +95,9 @@ TEST(AddressSanitizer, StrLenOOBTest) {
free(heap_string);
}
+// 32-bit android libc++-based NDK toolchain links wcslen statically, disabling
+// the interceptor.
+#if !defined(__ANDROID__) || defined(__LP64__)
TEST(AddressSanitizer, WcsLenTest) {
EXPECT_EQ(0U, wcslen(Ident(L"")));
size_t hello_len = 13;
@@ -106,6 +109,7 @@ TEST(AddressSanitizer, WcsLenTest) {
EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
free(heap_string);
}
+#endif
#if SANITIZER_TEST_HAS_STRNLEN
TEST(AddressSanitizer, StrNLenOOBTest) {
@@ -629,5 +633,3 @@ TEST(AddressSanitizer, StrtolOOBTest) {
RunStrtolOOBTest(&CallStrtol);
}
#endif
-
-
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 7e9cf3babc67..ed000327f126 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -13,6 +13,17 @@
#include "asan_test_utils.h"
#include <errno.h>
+#include <stdarg.h>
+
+#ifdef _LIBCPP_GET_C_LOCALE
+#define SANITIZER_GET_C_LOCALE _LIBCPP_GET_C_LOCALE
+#else
+#if defined(__FreeBSD__)
+#define SANITIZER_GET_C_LOCALE 0
+#elif defined(__NetBSD__)
+#define SANITIZER_GET_C_LOCALE LC_C_LOCALE
+#endif
+#endif
NOINLINE void *malloc_fff(size_t size) {
void *res = malloc/**/(size); break_optimization(0); return res;}
@@ -1328,19 +1339,18 @@ static int vsnprintf_l_wrapper(char *s, size_t n,
TEST(AddressSanitizer, snprintf_l) {
char buff[5];
// Check that snprintf_l() works fine with Asan.
- int res = snprintf_l(buff, 5,
- _LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()");
+ int res = snprintf_l(buff, 5, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()");
EXPECT_EQ(12, res);
// Check that vsnprintf_l() works fine with Asan.
- res = vsnprintf_l_wrapper(buff, 5,
- _LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()");
+ res = vsnprintf_l_wrapper(buff, 5, SANITIZER_GET_C_LOCALE, "%s",
+ "vsnprintf_l()");
EXPECT_EQ(13, res);
- EXPECT_DEATH(snprintf_l(buff, 10,
- _LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()"),
- "AddressSanitizer: stack-buffer-overflow");
- EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10,
- _LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()"),
- "AddressSanitizer: stack-buffer-overflow");
+ EXPECT_DEATH(
+ snprintf_l(buff, 10, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()"),
+ "AddressSanitizer: stack-buffer-overflow");
+ EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10, SANITIZER_GET_C_LOCALE, "%s",
+ "vsnprintf_l()"),
+ "AddressSanitizer: stack-buffer-overflow");
}
#endif
diff --git a/lib/asan/tests/asan_test_utils.h b/lib/asan/tests/asan_test_utils.h
index c292467220d4..d7b6f82e2978 100644
--- a/lib/asan/tests/asan_test_utils.h
+++ b/lib/asan/tests/asan_test_utils.h
@@ -45,7 +45,7 @@
#include <unistd.h>
#endif
-#if !defined(__APPLE__) && !defined(__FreeBSD__)
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
#include <malloc.h>
#endif
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index f0d3f50714c1..6fa958319121 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -51,7 +51,6 @@ set(GENERIC_SOURCES
cmpti2.c
comparedf2.c
comparesf2.c
- cpu_model.c
ctzdi2.c
ctzsi2.c
ctzti2.c
@@ -66,7 +65,6 @@ set(GENERIC_SOURCES
divtc3.c
divti3.c
divtf3.c
- divxc3.c
extendsfdf2.c
extendhfsf2.c
ffsdi2.c
@@ -84,27 +82,18 @@ set(GENERIC_SOURCES
fixunssfdi.c
fixunssfsi.c
fixunssfti.c
- fixunsxfdi.c
- fixunsxfsi.c
- fixunsxfti.c
- fixxfdi.c
- fixxfti.c
floatdidf.c
floatdisf.c
- floatdixf.c
floatsidf.c
floatsisf.c
floattidf.c
floattisf.c
- floattixf.c
floatundidf.c
floatundisf.c
- floatundixf.c
floatunsidf.c
floatunsisf.c
floatuntidf.c
floatuntisf.c
- floatuntixf.c
int_util.c
lshrdi3.c
lshrti3.c
@@ -124,7 +113,6 @@ set(GENERIC_SOURCES
mulvdi3.c
mulvsi3.c
mulvti3.c
- mulxc3.c
negdf2.c
negdi2.c
negsf2.c
@@ -142,7 +130,6 @@ set(GENERIC_SOURCES
powidf2.c
powisf2.c
powitf2.c
- powixf2.c
subdf3.c
subsf3.c
subvdi3.c
@@ -226,6 +213,23 @@ if (NOT FUCHSIA)
clear_cache.c)
endif()
+# These sources work on all x86 variants, but only x86 variants.
+set(x86_ARCH_SOURCES
+ cpu_model.c
+ divxc3.c
+ fixxfdi.c
+ fixxfti.c
+ fixunsxfdi.c
+ fixunsxfsi.c
+ fixunsxfti.c
+ floatdixf.c
+ floattixf.c
+ floatundixf.c
+ floatuntixf.c
+ mulxc3.c
+ powixf2.c
+)
+
if (NOT MSVC)
set(x86_64_SOURCES
x86_64/chkstk.S
@@ -235,8 +239,8 @@ if (NOT MSVC)
x86_64/floatdixf.c
x86_64/floatundidf.S
x86_64/floatundisf.S
- x86_64/floatundixf.S
- ${GENERIC_SOURCES})
+ x86_64/floatundixf.S)
+ filter_builtin_sources(x86_64_SOURCES EXCLUDE x86_64_SOURCES "${x86_64_SOURCES};${GENERIC_SOURCES}")
set(x86_64h_SOURCES ${x86_64_SOURCES})
if (WIN32)
@@ -262,8 +266,8 @@ if (NOT MSVC)
i386/moddi3.S
i386/muldi3.S
i386/udivdi3.S
- i386/umoddi3.S
- ${GENERIC_SOURCES})
+ i386/umoddi3.S)
+ filter_builtin_sources(i386_SOURCES EXCLUDE i386_SOURCES "${i386_SOURCES};${GENERIC_SOURCES}")
if (WIN32)
set(i386_SOURCES
@@ -271,9 +275,6 @@ if (NOT MSVC)
i386/chkstk.S
i386/chkstk2.S)
endif()
-
- set(i686_SOURCES
- ${i386_SOURCES})
else () # MSVC
# Use C versions of functions when building on MSVC
# MSVC's assembler takes Intel syntax, not AT&T syntax.
@@ -285,9 +286,13 @@ else () # MSVC
${GENERIC_SOURCES})
set(x86_64h_SOURCES ${x86_64_SOURCES})
set(i386_SOURCES ${GENERIC_SOURCES})
- set(i686_SOURCES ${i386_SOURCES})
endif () # if (NOT MSVC)
+set(x86_64h_SOURCES ${x86_64h_SOURCES} ${x86_ARCH_SOURCES})
+set(x86_64_SOURCES ${x86_64_SOURCES} ${x86_ARCH_SOURCES})
+set(i386_SOURCES ${i386_SOURCES} ${x86_ARCH_SOURCES})
+set(i686_SOURCES ${i686_SOURCES} ${x86_ARCH_SOURCES})
+
set(arm_SOURCES
arm/bswapdi2.S
arm/bswapsi2.S
@@ -319,8 +324,8 @@ set(arm_SOURCES
arm/sync_fetch_and_xor_8.S
arm/udivmodsi4.S
arm/udivsi3.S
- arm/umodsi3.S
- ${GENERIC_SOURCES})
+ arm/umodsi3.S)
+filter_builtin_sources(arm_SOURCES EXCLUDE arm_SOURCES "${arm_SOURCES};${GENERIC_SOURCES}")
set(thumb1_SOURCES
arm/divsi3.S
@@ -424,6 +429,7 @@ if(MINGW)
udivsi3.c
umoddi3.c
emutls.c)
+ filter_builtin_sources(arm_SOURCES EXCLUDE arm_SOURCES "${arm_SOURCES};${GENERIC_SOURCES}")
elseif(NOT WIN32)
# TODO the EABI sources should only be added to EABI targets
set(arm_SOURCES
@@ -458,8 +464,26 @@ set(mips64_SOURCES ${GENERIC_TF_SOURCES}
set(mips64el_SOURCES ${GENERIC_TF_SOURCES}
${mips_SOURCES})
-set(wasm32_SOURCES ${GENERIC_SOURCES})
-set(wasm64_SOURCES ${GENERIC_SOURCES})
+set(powerpc64_SOURCES
+ ppc/divtc3.c
+ ppc/fixtfdi.c
+ ppc/fixunstfdi.c
+ ppc/floatditf.c
+ ppc/floatunditf.c
+ ppc/gcc_qadd.c
+ ppc/gcc_qdiv.c
+ ppc/gcc_qmul.c
+ ppc/gcc_qsub.c
+ ppc/multc3.c
+ ${GENERIC_SOURCES})
+set(powerpc64le_SOURCES ${powerpc64_SOURCES})
+
+set(wasm32_SOURCES
+ ${GENERIC_TF_SOURCES}
+ ${GENERIC_SOURCES})
+set(wasm64_SOURCES
+ ${GENERIC_TF_SOURCES}
+ ${GENERIC_SOURCES})
add_custom_target(builtins)
set_target_properties(builtins PROPERTIES FOLDER "Compiler-RT Misc")
@@ -493,8 +517,10 @@ else ()
# NOTE: some architectures (e.g. i386) have multiple names. Ensure that
# we catch them all.
set(_arch ${arch})
- if("${arch}" STREQUAL "i686")
- set(_arch "i386|i686")
+ if("${arch}" STREQUAL "armv6m")
+ set(_arch "arm|armv6m")
+ elseif("${arch}" MATCHES "^(armhf|armv7|armv7s|armv7k|armv7m|armv7em)$")
+ set(_arch "arm")
endif()
# Filter out generic versions of routines that are re-implemented in
diff --git a/lib/builtins/adddf3.c b/lib/builtins/adddf3.c
index c528e9e21f51..9a3901312e51 100644
--- a/lib/builtins/adddf3.c
+++ b/lib/builtins/adddf3.c
@@ -20,8 +20,11 @@ COMPILER_RT_ABI double __adddf3(double a, double b){
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI double __aeabi_dadd(double a, double b) {
return __adddf3(a, b);
}
+#else
+AEABI_RTABI double __aeabi_dadd(double a, double b) COMPILER_RT_ALIAS(__adddf3);
+#endif
#endif
-
diff --git a/lib/builtins/addsf3.c b/lib/builtins/addsf3.c
index fe570687a25e..c5c1a41c3611 100644
--- a/lib/builtins/addsf3.c
+++ b/lib/builtins/addsf3.c
@@ -20,8 +20,11 @@ COMPILER_RT_ABI float __addsf3(float a, float b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI float __aeabi_fadd(float a, float b) {
return __addsf3(a, b);
}
+#else
+AEABI_RTABI float __aeabi_fadd(float a, float b) COMPILER_RT_ALIAS(__addsf3);
+#endif
#endif
-
diff --git a/lib/builtins/arm/aeabi_cdcmp.S b/lib/builtins/arm/aeabi_cdcmp.S
index 3e7a8b86b739..87dd03dce94d 100644
--- a/lib/builtins/arm/aeabi_cdcmp.S
+++ b/lib/builtins/arm/aeabi_cdcmp.S
@@ -30,7 +30,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
push {r0-r3, lr}
bl __aeabi_cdcmpeq_check_nan
cmp r0, #1
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
beq 1f
// NaN has been ruled out, so __aeabi_cdcmple can't trap
mov r0, sp
@@ -46,9 +46,12 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
pop {r0-r3, lr}
// NaN has been ruled out, so __aeabi_cdcmple can't trap
+ // Use "it ne" + unconditional branch to guarantee a supported relocation if
+ // __aeabi_cdcmple is in a different section for some builds.
+ IT(ne)
bne __aeabi_cdcmple
-#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+#if defined(USE_THUMB_2)
mov ip, #APSR_C
msr APSR_nzcvq, ip
#else
@@ -78,7 +81,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
bl __aeabi_dcmplt
cmp r0, #1
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
bne 1f
// Z = 0, C = 0
movs r0, #1
diff --git a/lib/builtins/arm/aeabi_cfcmp.S b/lib/builtins/arm/aeabi_cfcmp.S
index 1f304ffd964c..c5fee6b6a08e 100644
--- a/lib/builtins/arm/aeabi_cfcmp.S
+++ b/lib/builtins/arm/aeabi_cfcmp.S
@@ -30,7 +30,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
push {r0-r3, lr}
bl __aeabi_cfcmpeq_check_nan
cmp r0, #1
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
beq 1f
// NaN has been ruled out, so __aeabi_cfcmple can't trap
mov r0, sp
@@ -46,9 +46,12 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
pop {r0-r3, lr}
// NaN has been ruled out, so __aeabi_cfcmple can't trap
+ // Use "it ne" + unconditional branch to guarantee a supported relocation if
+ // __aeabi_cfcmple is in a different section for some builds.
+ IT(ne)
bne __aeabi_cfcmple
-#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+#if defined(USE_THUMB_2)
mov ip, #APSR_C
msr APSR_nzcvq, ip
#else
@@ -78,7 +81,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
bl __aeabi_fcmplt
cmp r0, #1
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
bne 1f
// Z = 0, C = 0
movs r0, #1
diff --git a/lib/builtins/arm/aeabi_idivmod.S b/lib/builtins/arm/aeabi_idivmod.S
index 0164b15dca18..9c9c80ab5a7b 100644
--- a/lib/builtins/arm/aeabi_idivmod.S
+++ b/lib/builtins/arm/aeabi_idivmod.S
@@ -20,16 +20,18 @@
#endif
.syntax unified
+ .text
+ DEFINE_CODE_STATE
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
push {r0, r1, lr}
bl SYMBOL_NAME(__divsi3)
pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom
muls r2, r0, r2 // r2 = quot * denom
subs r1, r1, r2
JMP (r3)
-#else
+#else // defined(USE_THUMB_1)
push { lr }
sub sp, sp, #4
mov r2, sp
@@ -42,7 +44,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
ldr r1, [sp]
add sp, sp, #4
pop { pc }
-#endif // __ARM_ARCH_ISA_THUMB == 1
+#endif // defined(USE_THUMB_1)
END_COMPILERRT_FUNCTION(__aeabi_idivmod)
NO_EXEC_STACK_DIRECTIVE
diff --git a/lib/builtins/arm/aeabi_memcmp.S b/lib/builtins/arm/aeabi_memcmp.S
index 33ea54848b26..e86d6113760e 100644
--- a/lib/builtins/arm/aeabi_memcmp.S
+++ b/lib/builtins/arm/aeabi_memcmp.S
@@ -14,7 +14,13 @@
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp)
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memcmp
+ pop {r7, pc}
+#else
b memcmp
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memcmp)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp)
diff --git a/lib/builtins/arm/aeabi_memcpy.S b/lib/builtins/arm/aeabi_memcpy.S
index eabfa490494c..e83c5fd4dbb3 100644
--- a/lib/builtins/arm/aeabi_memcpy.S
+++ b/lib/builtins/arm/aeabi_memcpy.S
@@ -14,7 +14,13 @@
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memcpy
+ pop {r7, pc}
+#else
b memcpy
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memcpy)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
diff --git a/lib/builtins/arm/aeabi_memmove.S b/lib/builtins/arm/aeabi_memmove.S
index 1bf08c0d5b75..ee28300e46f2 100644
--- a/lib/builtins/arm/aeabi_memmove.S
+++ b/lib/builtins/arm/aeabi_memmove.S
@@ -13,7 +13,13 @@
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memmove)
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memmove
+ pop {r7, pc}
+#else
b memmove
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memmove)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove)
diff --git a/lib/builtins/arm/aeabi_memset.S b/lib/builtins/arm/aeabi_memset.S
index 633f592279b5..0a678d7627e7 100644
--- a/lib/builtins/arm/aeabi_memset.S
+++ b/lib/builtins/arm/aeabi_memset.S
@@ -18,16 +18,29 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_memset)
mov r3, r1
mov r1, r2
mov r2, r3
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memset
+ pop {r7, pc}
+#else
b memset
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memset)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset)
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr)
mov r2, r1
movs r1, #0
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memset
+ pop {r7, pc}
+#else
b memset
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memclr)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr)
diff --git a/lib/builtins/arm/aeabi_uidivmod.S b/lib/builtins/arm/aeabi_uidivmod.S
index a627fc740a02..88a4a6d8bc12 100644
--- a/lib/builtins/arm/aeabi_uidivmod.S
+++ b/lib/builtins/arm/aeabi_uidivmod.S
@@ -21,9 +21,11 @@
#endif
.syntax unified
+ .text
+ DEFINE_CODE_STATE
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
cmp r0, r1
bcc LOCAL_LABEL(case_denom_larger)
push {r0, r1, lr}
@@ -36,7 +38,7 @@ LOCAL_LABEL(case_denom_larger):
movs r1, r0
movs r0, #0
JMP (lr)
-#else
+#else // defined(USE_THUMB_1)
push { lr }
sub sp, sp, #4
mov r2, sp
diff --git a/lib/builtins/arm/bswapdi2.S b/lib/builtins/arm/bswapdi2.S
index fb226cea249e..e9db8bac7994 100644
--- a/lib/builtins/arm/bswapdi2.S
+++ b/lib/builtins/arm/bswapdi2.S
@@ -11,9 +11,7 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
//
// extern uint64_t __bswapdi2(uint64_t);
@@ -21,11 +19,7 @@
// Reverse all the bytes in a 64-bit integer.
//
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2)
-#else
DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
-#endif
#if __ARM_ARCH < 6
// before armv6 does not have "rev" instruction
// r2 = rev(r0)
diff --git a/lib/builtins/arm/bswapsi2.S b/lib/builtins/arm/bswapsi2.S
index 553c3c2e39c8..1f6eed5c1bbf 100644
--- a/lib/builtins/arm/bswapsi2.S
+++ b/lib/builtins/arm/bswapsi2.S
@@ -11,9 +11,7 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
//
// extern uint32_t __bswapsi2(uint32_t);
@@ -21,11 +19,7 @@
// Reverse all the bytes in a 32-bit integer.
//
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2)
-#else
DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
-#endif
#if __ARM_ARCH < 6
// before armv6 does not have "rev" instruction
eor r1, r0, r0, ror #16
diff --git a/lib/builtins/arm/clzdi2.S b/lib/builtins/arm/clzdi2.S
index 6068c176fd15..fc03b385cdfa 100644
--- a/lib/builtins/arm/clzdi2.S
+++ b/lib/builtins/arm/clzdi2.S
@@ -15,17 +15,10 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
-
+ DEFINE_CODE_STATE
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2)
-#else
DEFINE_COMPILERRT_FUNCTION(__clzdi2)
-#endif
#ifdef __ARM_FEATURE_CLZ
#ifdef __ARMEB__
cmp r0, 0
diff --git a/lib/builtins/arm/clzsi2.S b/lib/builtins/arm/clzsi2.S
index c2ba3a8cfcda..f2ce59c90119 100644
--- a/lib/builtins/arm/clzsi2.S
+++ b/lib/builtins/arm/clzsi2.S
@@ -15,16 +15,10 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2)
-#else
DEFINE_COMPILERRT_FUNCTION(__clzsi2)
-#endif
#ifdef __ARM_FEATURE_CLZ
clz r0, r0
JMP(lr)
diff --git a/lib/builtins/arm/comparesf2.S b/lib/builtins/arm/comparesf2.S
index ef7091bf3c8f..c6c4cc067f07 100644
--- a/lib/builtins/arm/comparesf2.S
+++ b/lib/builtins/arm/comparesf2.S
@@ -38,10 +38,9 @@
//===----------------------------------------------------------------------===//
#include "../assembly.h"
-.syntax unified
-#if __ARM_ARCH_ISA_THUMB == 2
-.thumb
-#endif
+ .syntax unified
+ .text
+ DEFINE_CODE_STATE
@ int __eqsf2(float a, float b)
@@ -53,7 +52,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
#endif
// Make copies of a and b with the sign bit shifted off the top. These will
// be used to detect zeros and NaNs.
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
push {r6, lr}
lsls r2, r0, #1
lsls r3, r1, #1
@@ -67,7 +66,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
// flag if both a and b are zero (of either sign). The shift of r3 doesn't
// effect this at all, but it *does* make sure that the C flag is clear for
// the subsequent operations.
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
lsrs r6, r3, #1
orrs r6, r2
#else
@@ -75,7 +74,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
#endif
// Next, we check if a and b have the same or different signs. If they have
// opposite signs, this eor will set the N flag.
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
beq 1f
movs r6, r0
eors r6, r1
@@ -89,7 +88,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
// ignoring NaNs for now), this subtract will zero out r0. If they have the
// same sign, the flags are updated as they would be for a comparison of the
// absolute values of a and b.
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
bmi 1f
subs r0, r2, r3
1:
@@ -108,7 +107,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
// still clear from the shift argument in orrs; if a is positive and b
// negative, this places 0 in r0; if a is negative and b positive, -1 is
// placed in r0.
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
bhs 1f
// Here if a and b have the same sign and absA < absB, the result is thus
// b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan).
@@ -127,7 +126,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
// the sign of b in r0. Thus, if both are negative and a < b, -1 is placed
// in r0, which is the desired result. Conversely, if both are positive
// and a > b, zero is placed in r0.
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
bls 1f
// Here both have the same sign and absA > absB.
movs r0, #1
@@ -145,14 +144,14 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
// If a == b, then the Z flag is set, so we can get the correct final value
// into r0 by simply or'ing with 1 if Z is clear.
// For Thumb-1, r0 contains -1 if a < b, 0 if a > b and 0 if a == b.
-#if __ARM_ARCH_ISA_THUMB != 1
+#if !defined(USE_THUMB_1)
it ne
orrne r0, r0, #1
#endif
// Finally, we need to deal with NaNs. If either argument is NaN, replace
// the value in r0 with 1.
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
LOCAL_LABEL(CHECK_NAN):
movs r6, #0xff
lsls r6, #24
@@ -189,7 +188,7 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2)
vmov r0, s0
vmov r1, s1
#endif
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
push {r6, lr}
lsls r2, r0, #1
lsls r3, r1, #1
@@ -255,6 +254,7 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2)
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__unordsf2)
+
#if defined(COMPILER_RT_ARMHF_TARGET)
vmov r0, s0
vmov r1, s1
@@ -263,7 +263,7 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2)
lsls r2, r0, #1
lsls r3, r1, #1
movs r0, #0
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
movs r1, #0xff
lsls r1, #24
cmp r2, r1
diff --git a/lib/builtins/arm/divmodsi4.S b/lib/builtins/arm/divmodsi4.S
index 999c310ec8a3..8a027b741efe 100644
--- a/lib/builtins/arm/divmodsi4.S
+++ b/lib/builtins/arm/divmodsi4.S
@@ -23,20 +23,14 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
@ int __divmodsi4(int divident, int divisor, int *remainder)
@ Calculate the quotient and remainder of the (signed) division. The return
@ value is the quotient, the remainder is placed in the variable.
.p2align 3
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4)
-#else
DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divzero)
diff --git a/lib/builtins/arm/divsi3.S b/lib/builtins/arm/divsi3.S
index f066f60ad96d..19757af177eb 100644
--- a/lib/builtins/arm/divsi3.S
+++ b/lib/builtins/arm/divsi3.S
@@ -20,11 +20,9 @@
#define CLEAR_FRAME_AND_RETURN \
pop {r4, r7, pc}
- .syntax unified
- .text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ .syntax unified
+ .text
+ DEFINE_CODE_STATE
.p2align 3
// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
@@ -33,11 +31,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3)
@ int __divsi3(int divident, int divisor)
@ Calculate and return the quotient of the (signed) division.
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3)
-#else
DEFINE_COMPILERRT_FUNCTION(__divsi3)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1,r1
beq LOCAL_LABEL(divzero)
@@ -49,14 +43,14 @@ LOCAL_LABEL(divzero):
#else
ESTABLISH_FRAME
// Set aside the sign of the quotient.
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
movs r4, r0
eors r4, r1
# else
eor r4, r0, r1
# endif
// Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
asrs r2, r0, #31
asrs r3, r1, #31
eors r0, r2
@@ -72,7 +66,7 @@ ESTABLISH_FRAME
// abs(a) / abs(b)
bl SYMBOL_NAME(__udivsi3)
// Apply sign of quotient to result and return.
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
asrs r4, #31
eors r0, r4
subs r0, r0, r4
diff --git a/lib/builtins/arm/modsi3.S b/lib/builtins/arm/modsi3.S
index 1d302edc67bd..be263834d7f1 100644
--- a/lib/builtins/arm/modsi3.S
+++ b/lib/builtins/arm/modsi3.S
@@ -22,19 +22,13 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
@ int __modsi3(int divident, int divisor)
@ Calculate and return the remainder of the (signed) division.
.p2align 3
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3)
-#else
DEFINE_COMPILERRT_FUNCTION(__modsi3)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divzero)
diff --git a/lib/builtins/arm/udivmodsi4.S b/lib/builtins/arm/udivmodsi4.S
index 1ad8ee34bdef..ee3950c9b0eb 100644
--- a/lib/builtins/arm/udivmodsi4.S
+++ b/lib/builtins/arm/udivmodsi4.S
@@ -16,10 +16,7 @@
.syntax unified
.text
-
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
@ unsigned int *remainder)
@@ -27,11 +24,7 @@
@ value is the quotient, the remainder is placed in the variable.
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
-#else
DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divby0)
@@ -67,7 +60,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
clz r3, r1
/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
sub r3, r3, ip
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
adr ip, LOCAL_LABEL(div0block) + 1
sub ip, ip, r3, lsl #1
# else
@@ -78,7 +71,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
mov r3, #0
bx ip
# else
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
# error THUMB mode requires CLZ or UDIV
# endif
str r4, [sp, #-8]!
diff --git a/lib/builtins/arm/udivsi3.S b/lib/builtins/arm/udivsi3.S
index b97b3080bff4..6dea27d404ff 100644
--- a/lib/builtins/arm/udivsi3.S
+++ b/lib/builtins/arm/udivsi3.S
@@ -17,9 +17,7 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+DEFINE_CODE_STATE
.p2align 2
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
@@ -27,11 +25,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
@ unsigned int __udivsi3(unsigned int divident, unsigned int divisor)
@ Calculate and return the quotient of the (unsigned) division.
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3)
-#else
DEFINE_COMPILERRT_FUNCTION(__udivsi3)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divby0)
@@ -49,7 +43,7 @@ LOCAL_LABEL(divby0):
#else /* ! __ARM_ARCH_EXT_IDIV__ */
cmp r1, #1
bcc LOCAL_LABEL(divby0)
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
bne LOCAL_LABEL(num_neq_denom)
JMP(lr)
LOCAL_LABEL(num_neq_denom):
@@ -58,7 +52,7 @@ LOCAL_LABEL(num_neq_denom):
JMPc(lr, eq)
#endif
cmp r0, r1
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
bhs LOCAL_LABEL(num_ge_denom)
movs r0, #0
JMP(lr)
@@ -90,7 +84,7 @@ LOCAL_LABEL(num_ge_denom):
clz r3, r1
/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
sub r3, r3, ip
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
adr ip, LOCAL_LABEL(div0block) + 1
sub ip, ip, r3, lsl #1
# else
@@ -101,17 +95,17 @@ LOCAL_LABEL(num_ge_denom):
mov r3, #0
bx ip
# else /* No CLZ Feature */
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
# error THUMB mode requires CLZ or UDIV
# endif
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
# define BLOCK_SIZE 10
# else
# define BLOCK_SIZE 12
# endif
mov r2, r0
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
mov ip, r0
adr r0, LOCAL_LABEL(div0block)
adds r0, #1
@@ -120,7 +114,7 @@ LOCAL_LABEL(num_ge_denom):
# endif
lsrs r3, r2, #16
cmp r3, r1
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
blo LOCAL_LABEL(skip_16)
movs r2, r3
subs r0, r0, #(16 * BLOCK_SIZE)
@@ -132,7 +126,7 @@ LOCAL_LABEL(skip_16):
lsrs r3, r2, #8
cmp r3, r1
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
blo LOCAL_LABEL(skip_8)
movs r2, r3
subs r0, r0, #(8 * BLOCK_SIZE)
@@ -144,7 +138,7 @@ LOCAL_LABEL(skip_8):
lsrs r3, r2, #4
cmp r3, r1
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
blo LOCAL_LABEL(skip_4)
movs r2, r3
subs r0, r0, #(4 * BLOCK_SIZE)
@@ -156,7 +150,7 @@ LOCAL_LABEL(skip_4):
lsrs r3, r2, #2
cmp r3, r1
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
blo LOCAL_LABEL(skip_2)
movs r2, r3
subs r0, r0, #(2 * BLOCK_SIZE)
@@ -167,7 +161,7 @@ LOCAL_LABEL(skip_2):
# endif
/* Last block, no need to update r2 or r3. */
-# if __ARM_ARCH_ISA_THUMB == 1
+# if defined(USE_THUMB_1)
lsrs r3, r2, #1
cmp r3, r1
blo LOCAL_LABEL(skip_1)
@@ -203,7 +197,7 @@ LOCAL_LABEL(divby0):
# endif
-#if __ARM_ARCH_ISA_THUMB == 1
+#if defined(USE_THUMB_1)
#define block(shift) \
lsls r2, r1, IMM shift; \
cmp r0, r2; \
diff --git a/lib/builtins/arm/umodsi3.S b/lib/builtins/arm/umodsi3.S
index 672487e81a63..069fad34cb9c 100644
--- a/lib/builtins/arm/umodsi3.S
+++ b/lib/builtins/arm/umodsi3.S
@@ -16,19 +16,13 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
@ unsigned int __umodsi3(unsigned int divident, unsigned int divisor)
@ Calculate and return the remainder of the (unsigned) division.
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3)
-#else
DEFINE_COMPILERRT_FUNCTION(__umodsi3)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divby0)
@@ -65,7 +59,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3)
clz r3, r1
/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
sub r3, r3, ip
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
adr ip, LOCAL_LABEL(div0block) + 1
sub ip, ip, r3, lsl #1
# else
@@ -74,7 +68,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3)
sub ip, ip, r3, lsl #3
bx ip
# else
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
# error THUMB mode requires CLZ or UDIV
# endif
mov r2, r0
diff --git a/lib/builtins/ashldi3.c b/lib/builtins/ashldi3.c
index fcb0abdb1fce..a5c1836006b9 100644
--- a/lib/builtins/ashldi3.c
+++ b/lib/builtins/ashldi3.c
@@ -41,8 +41,5 @@ __ashldi3(di_int a, si_int b)
}
#if defined(__ARM_EABI__)
-AEABI_RTABI di_int __aeabi_llsl(di_int a, si_int b) {
- return __ashldi3(a, b);
-}
+AEABI_RTABI di_int __aeabi_llsl(di_int a, si_int b) COMPILER_RT_ALIAS(__ashldi3);
#endif
-
diff --git a/lib/builtins/ashrdi3.c b/lib/builtins/ashrdi3.c
index b4ab4c617ba0..84619965eca0 100644
--- a/lib/builtins/ashrdi3.c
+++ b/lib/builtins/ashrdi3.c
@@ -42,8 +42,5 @@ __ashrdi3(di_int a, si_int b)
}
#if defined(__ARM_EABI__)
-AEABI_RTABI di_int __aeabi_lasr(di_int a, si_int b) {
- return __ashrdi3(a, b);
-}
+AEABI_RTABI di_int __aeabi_lasr(di_int a, si_int b) COMPILER_RT_ALIAS(__ashrdi3);
#endif
-
diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h
index b15da52345c8..3f5e59b25442 100644
--- a/lib/builtins/assembly.h
+++ b/lib/builtins/assembly.h
@@ -68,10 +68,42 @@
#endif
#if defined(__arm__)
+
+/*
+ * Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
+ * - for '-mthumb -march=armv6' compiler defines '__thumb__'
+ * - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
+ */
+#if defined(__thumb2__) || defined(__thumb__)
+#define DEFINE_CODE_STATE .thumb SEPARATOR
+#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
+#if defined(__thumb2__)
+#define USE_THUMB_2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#define ITE(cond) ite cond
+#else
+#define USE_THUMB_1
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif // defined(__thumb__2)
+#else // !defined(__thumb2__) && !defined(__thumb__)
+#define DEFINE_CODE_STATE .arm SEPARATOR
+#define DECLARE_FUNC_ENCODING
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif
+
+#if defined(USE_THUMB_1) && defined(USE_THUMB_2)
+#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together."
+#endif
+
#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
#define ARM_HAS_BX
#endif
-#if !defined(__ARM_FEATURE_CLZ) && __ARM_ARCH_ISA_THUMB != 1 && \
+#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \
(__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
#define __ARM_FEATURE_CLZ
#endif
@@ -93,21 +125,14 @@
JMP(ip)
#endif
-#if __ARM_ARCH_ISA_THUMB == 2
-#define IT(cond) it cond
-#define ITT(cond) itt cond
-#define ITE(cond) ite cond
-#else
-#define IT(cond)
-#define ITT(cond)
-#define ITE(cond)
-#endif
-
-#if __ARM_ARCH_ISA_THUMB == 2
+#if defined(USE_THUMB_2)
#define WIDE(op) op.w
#else
#define WIDE(op) op
#endif
+#else // !defined(__arm)
+#define DECLARE_FUNC_ENCODING
+#define DEFINE_CODE_STATE
#endif
#define GLUE2(a, b) a##b
@@ -122,13 +147,16 @@
#endif
#define DEFINE_COMPILERRT_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY(name) \
+ DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
@@ -137,16 +165,20 @@
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
.globl name SEPARATOR \
SYMBOL_IS_FUNC(name) SEPARATOR \
HIDDEN(name) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
name:
#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c
index 25570fc2157a..4a01cb46d4ac 100644
--- a/lib/builtins/clear_cache.c
+++ b/lib/builtins/clear_cache.c
@@ -9,6 +9,7 @@
*/
#include "int_lib.h"
+#include <assert.h>
#include <stddef.h>
#if __APPLE__
@@ -23,7 +24,7 @@ uint32_t FlushInstructionCache(uintptr_t hProcess, void *lpBaseAddress,
uintptr_t GetCurrentProcess(void);
#endif
-#if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__)
+#if defined(__FreeBSD__) && defined(__arm__)
#include <sys/types.h>
#include <machine/sysarch.h>
#endif
@@ -32,7 +33,7 @@ uintptr_t GetCurrentProcess(void);
#include <machine/sysarch.h>
#endif
-#if defined(__mips__)
+#if defined(__linux__) && defined(__mips__)
#include <sys/cachectl.h>
#include <sys/syscall.h>
#include <unistd.h>
@@ -41,7 +42,7 @@ uintptr_t GetCurrentProcess(void);
* clear_mips_cache - Invalidates instruction cache for Mips.
*/
static void clear_mips_cache(const void* Addr, size_t Size) {
- asm volatile (
+ __asm__ volatile (
".set push\n"
".set noreorder\n"
".set noat\n"
@@ -96,7 +97,7 @@ void __clear_cache(void *start, void *end) {
* so there is nothing to do
*/
#elif defined(__arm__) && !defined(__APPLE__)
- #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Bitrig__)
+ #if defined(__FreeBSD__) || defined(__NetBSD__)
struct arm_sync_icache_args arg;
arg.addr = (uintptr_t)start;
@@ -121,15 +122,13 @@ void __clear_cache(void *start, void *end) {
: "=r"(start_reg)
: "r"(syscall_nr), "r"(start_reg), "r"(end_reg),
"r"(flags));
- if (start_reg != 0) {
- compilerrt_abort();
- }
+ assert(start_reg == 0 && "Cache flush syscall failed.");
#elif defined(_WIN32)
FlushInstructionCache(GetCurrentProcess(), start, end - start);
#else
compilerrt_abort();
#endif
-#elif defined(__mips__)
+#elif defined(__linux__) && defined(__mips__)
const uintptr_t start_int = (uintptr_t) start;
const uintptr_t end_int = (uintptr_t) end;
#if defined(__ANDROID__) && defined(__LP64__)
@@ -165,6 +164,21 @@ void __clear_cache(void *start, void *end) {
for (addr = xstart; addr < xend; addr += icache_line_size)
__asm __volatile("ic ivau, %0" :: "r"(addr));
__asm __volatile("isb sy");
+#elif defined (__powerpc64__)
+ const size_t line_size = 32;
+ const size_t len = (uintptr_t)end - (uintptr_t)start;
+
+ const uintptr_t mask = ~(line_size - 1);
+ const uintptr_t start_line = ((uintptr_t)start) & mask;
+ const uintptr_t end_line = ((uintptr_t)start + len + line_size - 1) & mask;
+
+ for (uintptr_t line = start_line; line < end_line; line += line_size)
+ __asm__ volatile("dcbf 0, %0" : : "r"(line));
+ __asm__ volatile("sync");
+
+ for (uintptr_t line = start_line; line < end_line; line += line_size)
+ __asm__ volatile("icbi 0, %0" : : "r"(line));
+ __asm__ volatile("isync");
#else
#if __APPLE__
/* On Darwin, sys_icache_invalidate() provides this functionality */
@@ -174,4 +188,3 @@ void __clear_cache(void *start, void *end) {
#endif
#endif
}
-
diff --git a/lib/builtins/comparedf2.c b/lib/builtins/comparedf2.c
index c5bb169d0021..44e5d2b288a6 100644
--- a/lib/builtins/comparedf2.c
+++ b/lib/builtins/comparedf2.c
@@ -143,8 +143,11 @@ __gtdf2(fp_t a, fp_t b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI int __aeabi_dcmpun(fp_t a, fp_t b) {
return __unorddf2(a, b);
}
+#else
+AEABI_RTABI int __aeabi_dcmpun(fp_t a, fp_t b) COMPILER_RT_ALIAS(__unorddf2);
+#endif
#endif
-
diff --git a/lib/builtins/comparesf2.c b/lib/builtins/comparesf2.c
index 4badb5e1b9f7..43cd6a6a7003 100644
--- a/lib/builtins/comparesf2.c
+++ b/lib/builtins/comparesf2.c
@@ -143,8 +143,11 @@ __gtsf2(fp_t a, fp_t b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI int __aeabi_fcmpun(fp_t a, fp_t b) {
return __unordsf2(a, b);
}
+#else
+AEABI_RTABI int __aeabi_fcmpun(fp_t a, fp_t b) COMPILER_RT_ALIAS(__unordsf2);
+#endif
#endif
-
diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c
index 83ea7a49faf7..4c96e9cd85d5 100644
--- a/lib/builtins/cpu_model.c
+++ b/lib/builtins/cpu_model.c
@@ -54,6 +54,7 @@ enum ProcessorTypes {
AMD_BTVER1,
AMD_BTVER2,
AMDFAM17H,
+ INTEL_KNM,
CPU_TYPE_MAX
};
@@ -74,6 +75,7 @@ enum ProcessorSubtypes {
INTEL_COREI7_BROADWELL,
INTEL_COREI7_SKYLAKE,
INTEL_COREI7_SKYLAKE_AVX512,
+ INTEL_COREI7_CANNONLAKE,
CPU_SUBTYPE_MAX
};
@@ -339,6 +341,12 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
*Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512"
break;
+ // Cannonlake:
+ case 0x66:
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_CANNONLAKE; // "cannonlake"
+ break;
+
case 0x1c: // Most 45 nm Intel Atom processors
case 0x26: // 45 nm Atom Lincroft
case 0x27: // 32 nm Atom Medfield
@@ -361,6 +369,10 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
*Type = INTEL_KNL; // knl
break;
+ case 0x85:
+ *Type = INTEL_KNM; // knm
+ break;
+
default: // Unknown family 6 CPU.
break;
break;
diff --git a/lib/builtins/divdf3.c b/lib/builtins/divdf3.c
index 492e32b851e9..04a4dc5571ca 100644
--- a/lib/builtins/divdf3.c
+++ b/lib/builtins/divdf3.c
@@ -183,8 +183,11 @@ __divdf3(fp_t a, fp_t b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_ddiv(fp_t a, fp_t b) {
return __divdf3(a, b);
}
+#else
+AEABI_RTABI fp_t __aeabi_ddiv(fp_t a, fp_t b) COMPILER_RT_ALIAS(__divdf3);
+#endif
#endif
-
diff --git a/lib/builtins/divsf3.c b/lib/builtins/divsf3.c
index aa6289a6d70a..65294d70fc61 100644
--- a/lib/builtins/divsf3.c
+++ b/lib/builtins/divsf3.c
@@ -167,8 +167,11 @@ __divsf3(fp_t a, fp_t b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_fdiv(fp_t a, fp_t b) {
return __divsf3(a, b);
}
+#else
+AEABI_RTABI fp_t __aeabi_fdiv(fp_t a, fp_t b) COMPILER_RT_ALIAS(__divsf3);
+#endif
#endif
-
diff --git a/lib/builtins/divsi3.c b/lib/builtins/divsi3.c
index 3852e3990b5b..75aea008ddc1 100644
--- a/lib/builtins/divsi3.c
+++ b/lib/builtins/divsi3.c
@@ -35,8 +35,5 @@ __divsi3(si_int a, si_int b)
}
#if defined(__ARM_EABI__)
-AEABI_RTABI si_int __aeabi_idiv(si_int a, si_int b) {
- return __divsi3(a, b);
-}
+AEABI_RTABI si_int __aeabi_idiv(si_int a, si_int b) COMPILER_RT_ALIAS(__divsi3);
#endif
-
diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c
index 12aad3a42b76..5dd8dd154771 100644
--- a/lib/builtins/emutls.c
+++ b/lib/builtins/emutls.c
@@ -102,7 +102,6 @@ static __inline emutls_address_array* emutls_getspecific() {
#include <malloc.h>
#include <stdio.h>
#include <assert.h>
-#include <immintrin.h>
static LPCRITICAL_SECTION emutls_mutex;
static DWORD emutls_tls_index = TLS_OUT_OF_INDEXES;
@@ -203,25 +202,24 @@ static __inline emutls_address_array* emutls_getspecific() {
/* Provide atomic load/store functions for emutls_get_index if built with MSVC.
*/
#if !defined(__ATOMIC_RELEASE)
+#include <intrin.h>
enum { __ATOMIC_ACQUIRE = 2, __ATOMIC_RELEASE = 3 };
static __inline uintptr_t __atomic_load_n(void *ptr, unsigned type) {
assert(type == __ATOMIC_ACQUIRE);
+ // These return the previous value - but since we do an OR with 0,
+ // it's equivalent to a plain load.
#ifdef _WIN64
- return (uintptr_t) _load_be_u64(ptr);
+ return InterlockedOr64(ptr, 0);
#else
- return (uintptr_t) _load_be_u32(ptr);
+ return InterlockedOr(ptr, 0);
#endif
}
static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) {
assert(type == __ATOMIC_RELEASE);
-#ifdef _WIN64
- _store_be_u64(ptr, val);
-#else
- _store_be_u32(ptr, val);
-#endif
+ InterlockedExchangePointer((void *volatile *)ptr, (void *)val);
}
#endif
diff --git a/lib/builtins/enable_execute_stack.c b/lib/builtins/enable_execute_stack.c
index 0dc3482c4467..327d460b4253 100644
--- a/lib/builtins/enable_execute_stack.c
+++ b/lib/builtins/enable_execute_stack.c
@@ -22,7 +22,7 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
#else
#ifndef __APPLE__
#include <unistd.h>
diff --git a/lib/builtins/extendhfsf2.c b/lib/builtins/extendhfsf2.c
index e7d9fde8abfc..d9c0db84b0ce 100644
--- a/lib/builtins/extendhfsf2.c
+++ b/lib/builtins/extendhfsf2.c
@@ -23,8 +23,11 @@ COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI float __aeabi_h2f(uint16_t a) {
return __extendhfsf2(a);
}
+#else
+AEABI_RTABI float __aeabi_h2f(uint16_t a) COMPILER_RT_ALIAS(__extendhfsf2);
+#endif
#endif
-
diff --git a/lib/builtins/extendsfdf2.c b/lib/builtins/extendsfdf2.c
index b9e7a7471a98..3d84529a6c53 100644
--- a/lib/builtins/extendsfdf2.c
+++ b/lib/builtins/extendsfdf2.c
@@ -17,8 +17,11 @@ COMPILER_RT_ABI double __extendsfdf2(float a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI double __aeabi_f2d(float a) {
return __extendsfdf2(a);
}
+#else
+AEABI_RTABI double __aeabi_f2d(float a) COMPILER_RT_ALIAS(__extendsfdf2);
+#endif
#endif
-
diff --git a/lib/builtins/fixdfdi.c b/lib/builtins/fixdfdi.c
index 31d76df28255..54e312d3c8f7 100644
--- a/lib/builtins/fixdfdi.c
+++ b/lib/builtins/fixdfdi.c
@@ -45,13 +45,11 @@ __fixdfdi(fp_t a) {
#endif
#if defined(__ARM_EABI__)
-AEABI_RTABI di_int
-#if defined(__SOFT_FP__)
-__aeabi_d2lz(fp_t a) {
-#else
-__aeabi_d2lz(double a) {
-#endif
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI di_int __aeabi_d2lz(fp_t a) {
return __fixdfdi(a);
}
+#else
+AEABI_RTABI di_int __aeabi_d2lz(fp_t a) COMPILER_RT_ALIAS(__fixdfdi);
+#endif
#endif
-
diff --git a/lib/builtins/fixdfsi.c b/lib/builtins/fixdfsi.c
index fc316dcd0545..5b9588175717 100644
--- a/lib/builtins/fixdfsi.c
+++ b/lib/builtins/fixdfsi.c
@@ -20,8 +20,11 @@ __fixdfsi(fp_t a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI si_int __aeabi_d2iz(fp_t a) {
return __fixdfsi(a);
}
+#else
+AEABI_RTABI si_int __aeabi_d2iz(fp_t a) COMPILER_RT_ALIAS(__fixdfsi);
+#endif
#endif
-
diff --git a/lib/builtins/fixsfdi.c b/lib/builtins/fixsfdi.c
index c43473637d60..32e87c60889f 100644
--- a/lib/builtins/fixsfdi.c
+++ b/lib/builtins/fixsfdi.c
@@ -45,13 +45,11 @@ __fixsfdi(fp_t a) {
#endif
#if defined(__ARM_EABI__)
-AEABI_RTABI di_int
-#if defined(__SOFT_FP__)
-__aeabi_f2lz(fp_t a) {
-#else
-__aeabi_f2lz(float a) {
-#endif
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI di_int __aeabi_f2lz(fp_t a) {
return __fixsfdi(a);
}
+#else
+AEABI_RTABI di_int __aeabi_f2lz(fp_t a) COMPILER_RT_ALIAS(__fixsfdi);
+#endif
#endif
-
diff --git a/lib/builtins/fixsfsi.c b/lib/builtins/fixsfsi.c
index 3276df966460..e94e5f3dcd68 100644
--- a/lib/builtins/fixsfsi.c
+++ b/lib/builtins/fixsfsi.c
@@ -20,8 +20,11 @@ __fixsfsi(fp_t a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI si_int __aeabi_f2iz(fp_t a) {
return __fixsfsi(a);
}
+#else
+AEABI_RTABI si_int __aeabi_f2iz(fp_t a) COMPILER_RT_ALIAS(__fixsfsi);
+#endif
#endif
-
diff --git a/lib/builtins/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c
index b734409709bf..bfe4dbb25656 100644
--- a/lib/builtins/fixunsdfdi.c
+++ b/lib/builtins/fixunsdfdi.c
@@ -42,13 +42,11 @@ __fixunsdfdi(fp_t a) {
#endif
#if defined(__ARM_EABI__)
-AEABI_RTABI du_int
-#if defined(__SOFT_FP__)
-__aeabi_d2ulz(fp_t a) {
-#else
-__aeabi_d2ulz(double a) {
-#endif
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI du_int __aeabi_d2ulz(fp_t a) {
return __fixunsdfdi(a);
}
+#else
+AEABI_RTABI du_int __aeabi_d2ulz(fp_t a) COMPILER_RT_ALIAS(__fixunsdfdi);
+#endif
#endif
-
diff --git a/lib/builtins/fixunsdfsi.c b/lib/builtins/fixunsdfsi.c
index bb3d8e0f831b..3c5355beae1a 100644
--- a/lib/builtins/fixunsdfsi.c
+++ b/lib/builtins/fixunsdfsi.c
@@ -19,8 +19,11 @@ __fixunsdfsi(fp_t a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI su_int __aeabi_d2uiz(fp_t a) {
return __fixunsdfsi(a);
}
+#else
+AEABI_RTABI su_int __aeabi_d2uiz(fp_t a) COMPILER_RT_ALIAS(__fixunsdfsi);
+#endif
#endif
-
diff --git a/lib/builtins/fixunssfdi.c b/lib/builtins/fixunssfdi.c
index 5d92245df0d9..080a25bb1e99 100644
--- a/lib/builtins/fixunssfdi.c
+++ b/lib/builtins/fixunssfdi.c
@@ -43,13 +43,11 @@ __fixunssfdi(fp_t a) {
#endif
#if defined(__ARM_EABI__)
-AEABI_RTABI du_int
-#if defined(__SOFT_FP__)
-__aeabi_f2ulz(fp_t a) {
-#else
-__aeabi_f2ulz(float a) {
-#endif
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI du_int __aeabi_f2ulz(fp_t a) {
return __fixunssfdi(a);
}
+#else
+AEABI_RTABI du_int __aeabi_f2ulz(fp_t a) COMPILER_RT_ALIAS(__fixunssfdi);
+#endif
#endif
-
diff --git a/lib/builtins/fixunssfsi.c b/lib/builtins/fixunssfsi.c
index 91d5e8ae5d7f..eca2916a5c88 100644
--- a/lib/builtins/fixunssfsi.c
+++ b/lib/builtins/fixunssfsi.c
@@ -23,8 +23,11 @@ __fixunssfsi(fp_t a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI su_int __aeabi_f2uiz(fp_t a) {
return __fixunssfsi(a);
}
+#else
+AEABI_RTABI su_int __aeabi_f2uiz(fp_t a) COMPILER_RT_ALIAS(__fixunssfsi);
+#endif
#endif
-
diff --git a/lib/builtins/floatdidf.c b/lib/builtins/floatdidf.c
index 681fecef9682..36b856e078d4 100644
--- a/lib/builtins/floatdidf.c
+++ b/lib/builtins/floatdidf.c
@@ -105,8 +105,11 @@ __floatdidf(di_int a)
#endif
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI double __aeabi_l2d(di_int a) {
return __floatdidf(a);
}
+#else
+AEABI_RTABI double __aeabi_l2d(di_int a) COMPILER_RT_ALIAS(__floatdidf);
+#endif
#endif
-
diff --git a/lib/builtins/floatdisf.c b/lib/builtins/floatdisf.c
index dd548165c373..a2f09eb2ed2c 100644
--- a/lib/builtins/floatdisf.c
+++ b/lib/builtins/floatdisf.c
@@ -78,8 +78,11 @@ __floatdisf(di_int a)
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI float __aeabi_l2f(di_int a) {
return __floatdisf(a);
}
+#else
+AEABI_RTABI float __aeabi_l2f(di_int a) COMPILER_RT_ALIAS(__floatdisf);
+#endif
#endif
-
diff --git a/lib/builtins/floatsidf.c b/lib/builtins/floatsidf.c
index 2ae395bdc1db..fe051123ce7c 100644
--- a/lib/builtins/floatsidf.c
+++ b/lib/builtins/floatsidf.c
@@ -51,8 +51,11 @@ __floatsidf(int a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_i2d(int a) {
return __floatsidf(a);
}
+#else
+AEABI_RTABI fp_t __aeabi_i2d(int a) COMPILER_RT_ALIAS(__floatsidf);
+#endif
#endif
-
diff --git a/lib/builtins/floatsisf.c b/lib/builtins/floatsisf.c
index 08891fcdf201..bf087ee3c295 100644
--- a/lib/builtins/floatsisf.c
+++ b/lib/builtins/floatsisf.c
@@ -57,8 +57,11 @@ __floatsisf(int a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_i2f(int a) {
return __floatsisf(a);
}
+#else
+AEABI_RTABI fp_t __aeabi_i2f(int a) COMPILER_RT_ALIAS(__floatsisf);
+#endif
#endif
-
diff --git a/lib/builtins/floatundidf.c b/lib/builtins/floatundidf.c
index 6c1a931ef2f3..8bc2a096324f 100644
--- a/lib/builtins/floatundidf.c
+++ b/lib/builtins/floatundidf.c
@@ -104,8 +104,11 @@ __floatundidf(du_int a)
#endif
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI double __aeabi_ul2d(du_int a) {
return __floatundidf(a);
}
+#else
+AEABI_RTABI double __aeabi_ul2d(du_int a) COMPILER_RT_ALIAS(__floatundidf);
+#endif
#endif
-
diff --git a/lib/builtins/floatundisf.c b/lib/builtins/floatundisf.c
index 86841a75dc66..844786ea7777 100644
--- a/lib/builtins/floatundisf.c
+++ b/lib/builtins/floatundisf.c
@@ -75,8 +75,11 @@ __floatundisf(du_int a)
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI float __aeabi_ul2f(du_int a) {
return __floatundisf(a);
}
+#else
+AEABI_RTABI float __aeabi_ul2f(du_int a) COMPILER_RT_ALIAS(__floatundisf);
+#endif
#endif
-
diff --git a/lib/builtins/floatunsidf.c b/lib/builtins/floatunsidf.c
index 8d4807194f0b..75cf6b9177df 100644
--- a/lib/builtins/floatunsidf.c
+++ b/lib/builtins/floatunsidf.c
@@ -40,8 +40,11 @@ __floatunsidf(unsigned int a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_ui2d(unsigned int a) {
return __floatunsidf(a);
}
+#else
+AEABI_RTABI fp_t __aeabi_ui2d(unsigned int a) COMPILER_RT_ALIAS(__floatunsidf);
+#endif
#endif
-
diff --git a/lib/builtins/floatunsisf.c b/lib/builtins/floatunsisf.c
index f194c046d2fb..29525ccedbbe 100644
--- a/lib/builtins/floatunsisf.c
+++ b/lib/builtins/floatunsisf.c
@@ -48,8 +48,11 @@ __floatunsisf(unsigned int a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_ui2f(unsigned int a) {
return __floatunsisf(a);
}
+#else
+AEABI_RTABI fp_t __aeabi_ui2f(unsigned int a) COMPILER_RT_ALIAS(__floatunsisf);
+#endif
#endif
-
diff --git a/lib/builtins/int_endianness.h b/lib/builtins/int_endianness.h
index 7995ddbb953c..e2586c56bac8 100644
--- a/lib/builtins/int_endianness.h
+++ b/lib/builtins/int_endianness.h
@@ -61,7 +61,7 @@
#endif /* *BSD */
-#if defined(__OpenBSD__) || defined(__Bitrig__)
+#if defined(__OpenBSD__)
#include <machine/endian.h>
#if _BYTE_ORDER == _BIG_ENDIAN
@@ -72,7 +72,7 @@
#define _YUGA_BIG_ENDIAN 0
#endif /* _BYTE_ORDER */
-#endif /* OpenBSD and Bitrig. */
+#endif /* OpenBSD */
/* .. */
diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h
index 9a8092d50d8e..9d09e2dc915b 100644
--- a/lib/builtins/int_lib.h
+++ b/lib/builtins/int_lib.h
@@ -22,9 +22,11 @@
#if defined(__ELF__)
#define FNALIAS(alias_name, original_name) \
- void alias_name() __attribute__((alias(#original_name)))
+ void alias_name() __attribute__((__alias__(#original_name)))
+#define COMPILER_RT_ALIAS(aliasee) __attribute__((__alias__(#aliasee)))
#else
#define FNALIAS(alias, name) _Pragma("GCC error(\"alias unsupported on this file format\")")
+#define COMPILER_RT_ALIAS(aliasee) _Pragma("GCC error(\"alias unsupported on this file format\")")
#endif
/* ABI macro definitions */
diff --git a/lib/builtins/lshrdi3.c b/lib/builtins/lshrdi3.c
index becbbef4eb09..67b2a7668345 100644
--- a/lib/builtins/lshrdi3.c
+++ b/lib/builtins/lshrdi3.c
@@ -41,8 +41,5 @@ __lshrdi3(di_int a, si_int b)
}
#if defined(__ARM_EABI__)
-AEABI_RTABI di_int __aeabi_llsr(di_int a, si_int b) {
- return __lshrdi3(a, b);
-}
+AEABI_RTABI di_int __aeabi_llsr(di_int a, si_int b) COMPILER_RT_ALIAS(__lshrdi3);
#endif
-
diff --git a/lib/builtins/muldf3.c b/lib/builtins/muldf3.c
index 59a60190eba3..1bb103e38c13 100644
--- a/lib/builtins/muldf3.c
+++ b/lib/builtins/muldf3.c
@@ -20,8 +20,11 @@ COMPILER_RT_ABI fp_t __muldf3(fp_t a, fp_t b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_dmul(fp_t a, fp_t b) {
return __muldf3(a, b);
}
+#else
+AEABI_RTABI fp_t __aeabi_dmul(fp_t a, fp_t b) COMPILER_RT_ALIAS(__muldf3);
+#endif
#endif
-
diff --git a/lib/builtins/muldi3.c b/lib/builtins/muldi3.c
index 6818a9e2f722..a187315e9165 100644
--- a/lib/builtins/muldi3.c
+++ b/lib/builtins/muldi3.c
@@ -54,8 +54,5 @@ __muldi3(di_int a, di_int b)
}
#if defined(__ARM_EABI__)
-AEABI_RTABI di_int __aeabi_lmul(di_int a, di_int b) {
- return __muldi3(a, b);
-}
+AEABI_RTABI di_int __aeabi_lmul(di_int a, di_int b) COMPILER_RT_ALIAS(__muldi3);
#endif
-
diff --git a/lib/builtins/mulsf3.c b/lib/builtins/mulsf3.c
index f141af1acc58..1e2cf3e717c9 100644
--- a/lib/builtins/mulsf3.c
+++ b/lib/builtins/mulsf3.c
@@ -20,8 +20,11 @@ COMPILER_RT_ABI fp_t __mulsf3(fp_t a, fp_t b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_fmul(fp_t a, fp_t b) {
return __mulsf3(a, b);
}
+#else
+AEABI_RTABI fp_t __aeabi_fmul(fp_t a, fp_t b) COMPILER_RT_ALIAS(__mulsf3);
+#endif
#endif
-
diff --git a/lib/builtins/negdf2.c b/lib/builtins/negdf2.c
index 5e2544cdb4be..f0bfaad24743 100644
--- a/lib/builtins/negdf2.c
+++ b/lib/builtins/negdf2.c
@@ -20,8 +20,11 @@ __negdf2(fp_t a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_dneg(fp_t a) {
return __negdf2(a);
}
+#else
+AEABI_RTABI fp_t __aeabi_dneg(fp_t a) COMPILER_RT_ALIAS(__negdf2);
+#endif
#endif
-
diff --git a/lib/builtins/negsf2.c b/lib/builtins/negsf2.c
index f90b34335680..05c97d4d5a11 100644
--- a/lib/builtins/negsf2.c
+++ b/lib/builtins/negsf2.c
@@ -20,8 +20,11 @@ __negsf2(fp_t a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_fneg(fp_t a) {
return __negsf2(a);
}
+#else
+AEABI_RTABI fp_t __aeabi_fneg(fp_t a) COMPILER_RT_ALIAS(__negsf2);
+#endif
#endif
-
diff --git a/lib/builtins/subdf3.c b/lib/builtins/subdf3.c
index 38340dfab1a6..a892fa603cf2 100644
--- a/lib/builtins/subdf3.c
+++ b/lib/builtins/subdf3.c
@@ -22,8 +22,11 @@ __subdf3(fp_t a, fp_t b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_dsub(fp_t a, fp_t b) {
return __subdf3(a, b);
}
+#else
+AEABI_RTABI fp_t __aeabi_dsub(fp_t a, fp_t b) COMPILER_RT_ALIAS(__subdf3);
+#endif
#endif
-
diff --git a/lib/builtins/subsf3.c b/lib/builtins/subsf3.c
index 34276b1447ba..4b2786177dcc 100644
--- a/lib/builtins/subsf3.c
+++ b/lib/builtins/subsf3.c
@@ -22,8 +22,11 @@ __subsf3(fp_t a, fp_t b) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI fp_t __aeabi_fsub(fp_t a, fp_t b) {
return __subsf3(a, b);
}
+#else
+AEABI_RTABI fp_t __aeabi_fsub(fp_t a, fp_t b) COMPILER_RT_ALIAS(__subsf3);
+#endif
#endif
-
diff --git a/lib/builtins/truncdfhf2.c b/lib/builtins/truncdfhf2.c
index 4bb71aa178a0..8354a41b8b6f 100644
--- a/lib/builtins/truncdfhf2.c
+++ b/lib/builtins/truncdfhf2.c
@@ -16,8 +16,11 @@ COMPILER_RT_ABI uint16_t __truncdfhf2(double a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI uint16_t __aeabi_d2h(double a) {
return __truncdfhf2(a);
}
+#else
+AEABI_RTABI uint16_t __aeabi_d2h(double a) COMPILER_RT_ALIAS(__truncdfhf2);
+#endif
#endif
-
diff --git a/lib/builtins/truncdfsf2.c b/lib/builtins/truncdfsf2.c
index 8bf58bb23a3b..195d3e0656e7 100644
--- a/lib/builtins/truncdfsf2.c
+++ b/lib/builtins/truncdfsf2.c
@@ -16,8 +16,11 @@ COMPILER_RT_ABI float __truncdfsf2(double a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI float __aeabi_d2f(double a) {
return __truncdfsf2(a);
}
+#else
+AEABI_RTABI float __aeabi_d2f(double a) COMPILER_RT_ALIAS(__truncdfsf2);
+#endif
#endif
-
diff --git a/lib/builtins/truncsfhf2.c b/lib/builtins/truncsfhf2.c
index f6ce1fa1de05..9c84ab4f938a 100644
--- a/lib/builtins/truncsfhf2.c
+++ b/lib/builtins/truncsfhf2.c
@@ -22,8 +22,11 @@ COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) {
}
#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
AEABI_RTABI uint16_t __aeabi_f2h(float a) {
return __truncsfhf2(a);
}
+#else
+AEABI_RTABI uint16_t __aeabi_f2h(float a) COMPILER_RT_ALIAS(__truncsfhf2);
+#endif
#endif
-
diff --git a/lib/builtins/udivsi3.c b/lib/builtins/udivsi3.c
index 8eccf102cc97..bb720f8c382b 100644
--- a/lib/builtins/udivsi3.c
+++ b/lib/builtins/udivsi3.c
@@ -64,8 +64,5 @@ __udivsi3(su_int n, su_int d)
}
#if defined(__ARM_EABI__)
-AEABI_RTABI su_int __aeabi_uidiv(su_int n, su_int d) {
- return __udivsi3(n, d);
-}
+AEABI_RTABI su_int __aeabi_uidiv(su_int n, su_int d) COMPILER_RT_ALIAS(__udivsi3);
#endif
-
diff --git a/lib/cfi/CMakeLists.txt b/lib/cfi/CMakeLists.txt
index 206400201466..6c531445626a 100644
--- a/lib/cfi/CMakeLists.txt
+++ b/lib/cfi/CMakeLists.txt
@@ -1,37 +1,39 @@
add_compiler_rt_component(cfi)
-set(CFI_SOURCES cfi.cc)
+if(OS_NAME MATCHES "Linux")
+ set(CFI_SOURCES cfi.cc)
-include_directories(..)
+ include_directories(..)
-set(CFI_CFLAGS
- ${SANITIZER_COMMON_CFLAGS}
-)
+ set(CFI_CFLAGS
+ ${SANITIZER_COMMON_CFLAGS}
+ )
-set(CFI_DIAG_CFLAGS
- -DCFI_ENABLE_DIAG=1
-)
+ set(CFI_DIAG_CFLAGS
+ -DCFI_ENABLE_DIAG=1
+ )
-foreach(arch ${CFI_SUPPORTED_ARCH})
- add_compiler_rt_runtime(clang_rt.cfi
- STATIC
- ARCHS ${arch}
- SOURCES ${CFI_SOURCES}
- OBJECT_LIBS RTInterception
- RTSanitizerCommon
- RTSanitizerCommonLibc
- CFLAGS ${CFI_CFLAGS}
- PARENT_TARGET cfi)
- add_compiler_rt_runtime(clang_rt.cfi_diag
- STATIC
- ARCHS ${arch}
- SOURCES ${CFI_SOURCES}
- OBJECT_LIBS RTInterception
- RTSanitizerCommon
- RTSanitizerCommonLibc
- RTUbsan
- CFLAGS ${CFI_CFLAGS} ${CFI_DIAG_CFLAGS}
- PARENT_TARGET cfi)
-endforeach()
+ foreach(arch ${CFI_SUPPORTED_ARCH})
+ add_compiler_rt_runtime(clang_rt.cfi
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${CFI_SOURCES}
+ OBJECT_LIBS RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ CFLAGS ${CFI_CFLAGS}
+ PARENT_TARGET cfi)
+ add_compiler_rt_runtime(clang_rt.cfi_diag
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${CFI_SOURCES}
+ OBJECT_LIBS RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTUbsan
+ CFLAGS ${CFI_CFLAGS} ${CFI_DIAG_CFLAGS}
+ PARENT_TARGET cfi)
+ endforeach()
+endif()
add_compiler_rt_resource_file(cfi_blacklist cfi_blacklist.txt cfi)
diff --git a/lib/cfi/cfi.cc b/lib/cfi/cfi.cc
index f720230a70be..f7693b37d29c 100644
--- a/lib/cfi/cfi.cc
+++ b/lib/cfi/cfi.cc
@@ -280,7 +280,7 @@ void InitShadow() {
CHECK_EQ(0, GetShadow());
CHECK_EQ(0, GetShadowSize());
- uptr vma = GetMaxVirtualAddress();
+ uptr vma = GetMaxUserVirtualAddress();
// Shadow is 2 -> 2**kShadowGranularity.
SetShadowSize((vma >> (kShadowGranularity - 1)) + 1);
VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize());
diff --git a/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt
index cc111be8120e..d8c9d49e3cdd 100644
--- a/lib/cfi/cfi_blacklist.txt
+++ b/lib/cfi/cfi_blacklist.txt
@@ -1,18 +1,4 @@
-# Standard library types.
-type:std::*
-
-# The stdext namespace contains Microsoft standard library extensions.
-type:stdext::*
-
-# Types with a uuid attribute, i.e. COM types.
-type:attr:uuid
-
-# STL allocators (T *allocator<T *>::allocate(size_type, const void*)).
-# The type signature mandates a cast from uninitialized void* to T*.
-# size_type can either be unsigned int (j) or unsigned long (m).
-fun:*8allocateEjPKv
-fun:*8allocateEmPKv
-
+[cfi-unrelated-cast]
# std::get_temporary_buffer, likewise (libstdc++, libc++).
fun:_ZSt20get_temporary_buffer*
fun:_ZNSt3__120get_temporary_buffer*
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index 3aa99b7f9c27..9e360c959fa7 100644
--- a/lib/dfsan/dfsan.cc
+++ b/lib/dfsan/dfsan.cc
@@ -21,6 +21,7 @@
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "sanitizer_common/sanitizer_libc.h"
diff --git a/lib/esan/esan_sideline.h b/lib/esan/esan_sideline.h
index aa3fae1db318..04aff22f4cf0 100644
--- a/lib/esan/esan_sideline.h
+++ b/lib/esan/esan_sideline.h
@@ -17,6 +17,7 @@
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
namespace __esan {
@@ -46,7 +47,8 @@ public:
private:
static int runSideline(void *Arg);
static void registerSignal(int SigNum);
- static void handleSidelineSignal(int SigNum, void *SigInfo, void *Ctx);
+ static void handleSidelineSignal(int SigNum, __sanitizer_siginfo *SigInfo,
+ void *Ctx);
char *Stack;
SidelineFunc sampleFunc;
diff --git a/lib/esan/esan_sideline_linux.cpp b/lib/esan/esan_sideline_linux.cpp
index bc272dfe49f8..4a96910ece35 100644
--- a/lib/esan/esan_sideline_linux.cpp
+++ b/lib/esan/esan_sideline_linux.cpp
@@ -40,7 +40,8 @@ static const uptr SidelineIdUninitialized = 1;
static SidelineThread *TheThread;
// We aren't passing SA_NODEFER so the same signal is blocked while here.
-void SidelineThread::handleSidelineSignal(int SigNum, void *SigInfo,
+void SidelineThread::handleSidelineSignal(int SigNum,
+ __sanitizer_siginfo *SigInfo,
void *Ctx) {
VPrintf(3, "Sideline signal %d\n", SigNum);
CHECK_EQ(SigNum, SIGALRM);
diff --git a/lib/esan/working_set_posix.cpp b/lib/esan/working_set_posix.cpp
index fcfa87128857..5ec53b959261 100644
--- a/lib/esan/working_set_posix.cpp
+++ b/lib/esan/working_set_posix.cpp
@@ -34,7 +34,7 @@ bool processWorkingSetSignal(int SigNum, void (*Handler)(int),
VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum);
if (SigNum == SIGSEGV) {
*Result = AppSigAct.handler;
- AppSigAct.sigaction = (void (*)(int, void*, void*))Handler;
+ AppSigAct.sigaction = (decltype(AppSigAct.sigaction))Handler;
return false; // Skip real call.
}
return true;
@@ -73,7 +73,7 @@ bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet) {
static void reinstateDefaultHandler(int SigNum) {
__sanitizer_sigaction SigAct;
internal_memset(&SigAct, 0, sizeof(SigAct));
- SigAct.sigaction = (void (*)(int, void*, void*)) SIG_DFL;
+ SigAct.sigaction = (decltype(SigAct.sigaction))SIG_DFL;
int Res = internal_sigaction(SigNum, &SigAct, nullptr);
CHECK(Res == 0);
VPrintf(1, "Unregistered for %d handler\n", SigNum);
@@ -81,7 +81,8 @@ static void reinstateDefaultHandler(int SigNum) {
// If this is a shadow fault, we handle it here; otherwise, we pass it to the
// app to handle it just as the app would do without our tool in place.
-static void handleMemoryFault(int SigNum, void *Info, void *Ctx) {
+static void handleMemoryFault(int SigNum, __sanitizer_siginfo *Info,
+ void *Ctx) {
if (SigNum == SIGSEGV) {
// We rely on si_addr being filled in (thus we do not support old kernels).
siginfo_t *SigInfo = (siginfo_t *)Info;
diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt
new file mode 100644
index 000000000000..9769be52ae01
--- /dev/null
+++ b/lib/fuzzer/CMakeLists.txt
@@ -0,0 +1,80 @@
+set(LIBFUZZER_SOURCES
+ FuzzerClangCounters.cpp
+ FuzzerCrossOver.cpp
+ FuzzerDriver.cpp
+ FuzzerExtFunctionsDlsym.cpp
+ FuzzerExtFunctionsDlsymWin.cpp
+ FuzzerExtFunctionsWeak.cpp
+ FuzzerExtraCounters.cpp
+ FuzzerIO.cpp
+ FuzzerIOPosix.cpp
+ FuzzerIOWindows.cpp
+ FuzzerLoop.cpp
+ FuzzerMerge.cpp
+ FuzzerMutate.cpp
+ FuzzerSHA1.cpp
+ FuzzerShmemPosix.cpp
+ FuzzerShmemWindows.cpp
+ FuzzerTracePC.cpp
+ FuzzerUtil.cpp
+ FuzzerUtilDarwin.cpp
+ FuzzerUtilFuchsia.cpp
+ FuzzerUtilLinux.cpp
+ FuzzerUtilPosix.cpp
+ FuzzerUtilWindows.cpp
+ )
+
+CHECK_CXX_SOURCE_COMPILES("
+ static thread_local int blah;
+ int main() {
+ return 0;
+ }
+ " HAS_THREAD_LOCAL)
+
+set(LIBFUZZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+
+append_list_if(COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG -fno-omit-frame-pointer LIBFUZZER_CFLAGS)
+
+if (CMAKE_CXX_FLAGS MATCHES "fsanitize-coverage")
+ list(APPEND LIBFUZZER_CFLAGS -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters)
+endif()
+
+if(NOT HAS_THREAD_LOCAL)
+ list(APPEND LIBFUZZER_CFLAGS -Dthread_local=__thread)
+endif()
+
+if(APPLE)
+ set(FUZZER_SUPPORTED_OS osx)
+endif()
+
+add_compiler_rt_object_libraries(RTfuzzer
+ OS ${FUZZER_SUPPORTED_OS}
+ ARCHS ${FUZZER_SUPPORTED_ARCH}
+ SOURCES ${LIBFUZZER_SOURCES}
+ CFLAGS ${LIBFUZZER_CFLAGS})
+
+add_compiler_rt_object_libraries(RTfuzzer_main
+ OS ${FUZZER_SUPPORTED_OS}
+ ARCHS ${FUZZER_SUPPORTED_ARCH}
+ SOURCES FuzzerMain.cpp
+ CFLAGS ${LIBFUZZER_CFLAGS})
+
+add_compiler_rt_runtime(clang_rt.fuzzer
+ STATIC
+ OS ${FUZZER_SUPPORTED_OS}
+ ARCHS ${FUZZER_SUPPORTED_ARCH}
+ OBJECT_LIBS RTfuzzer RTfuzzer_main
+ CFLAGS ${LIBFUZZER_CFLAGS}
+ PARENT_TARGET fuzzer)
+
+add_compiler_rt_runtime(clang_rt.fuzzer_no_main
+ STATIC
+ OS ${FUZZER_SUPPORTED_OS}
+ ARCHS ${FUZZER_SUPPORTED_ARCH}
+ OBJECT_LIBS RTfuzzer
+ CFLAGS ${LIBFUZZER_CFLAGS}
+ PARENT_TARGET fuzzer)
+
+if(COMPILER_RT_INCLUDE_TESTS)
+ add_subdirectory(tests)
+endif()
diff --git a/lib/fuzzer/FuzzerClangCounters.cpp b/lib/fuzzer/FuzzerClangCounters.cpp
new file mode 100644
index 000000000000..f69e922cf004
--- /dev/null
+++ b/lib/fuzzer/FuzzerClangCounters.cpp
@@ -0,0 +1,49 @@
+//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Coverage counters from Clang's SourceBasedCodeCoverage.
+//===----------------------------------------------------------------------===//
+
+// Support for SourceBasedCodeCoverage is experimental:
+// * Works only for the main binary, not DSOs yet.
+// * Works only on Linux.
+// * Does not implement print_pcs/print_coverage yet.
+// * Is not fully evaluated for performance and sensitivity.
+// We expect large performance drop due to 64-bit counters,
+// and *maybe* better sensitivity due to more fine-grained counters.
+// Preliminary comparison on a single benchmark (RE2) shows
+// a bit worse sensitivity though.
+
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_LINUX
+__attribute__((weak)) extern uint64_t __start___llvm_prf_cnts;
+__attribute__((weak)) extern uint64_t __stop___llvm_prf_cnts;
+namespace fuzzer {
+uint64_t *ClangCountersBegin() { return &__start___llvm_prf_cnts; }
+uint64_t *ClangCountersEnd() { return &__stop___llvm_prf_cnts; }
+} // namespace fuzzer
+#else
+// TODO: Implement on Mac (if the data shows it's worth it).
+//__attribute__((visibility("hidden")))
+//extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts");
+//__attribute__((visibility("hidden")))
+//extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts");
+namespace fuzzer {
+uint64_t *ClangCountersBegin() { return nullptr; }
+uint64_t *ClangCountersEnd() { return nullptr; }
+} // namespace fuzzer
+#endif
+
+namespace fuzzer {
+ATTRIBUTE_NO_SANITIZE_ALL
+void ClearClangCounters() { // hand-written memset, don't asan-ify.
+ for (auto P = ClangCountersBegin(); P < ClangCountersEnd(); P++)
+ *P = 0;
+}
+}
diff --git a/lib/fuzzer/FuzzerCommand.h b/lib/fuzzer/FuzzerCommand.h
new file mode 100644
index 000000000000..c5500ed21fc1
--- /dev/null
+++ b/lib/fuzzer/FuzzerCommand.h
@@ -0,0 +1,180 @@
+//===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// FuzzerCommand represents a command to run in a subprocess. It allows callers
+// to manage command line arguments and output and error streams.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_COMMAND_H
+#define LLVM_FUZZER_COMMAND_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace fuzzer {
+
+class Command final {
+public:
+ // This command line flag is used to indicate that the remaining command line
+ // is immutable, meaning this flag effectively marks the end of the mutable
+ // argument list.
+ static inline const char *ignoreRemainingArgs() {
+ static const char *kIgnoreRemaining = "-ignore_remaining_args=1";
+ return kIgnoreRemaining;
+ }
+
+ Command() : CombinedOutAndErr(false) {}
+
+ explicit Command(const Vector<std::string> &ArgsToAdd)
+ : Args(ArgsToAdd), CombinedOutAndErr(false) {}
+
+ explicit Command(const Command &Other)
+ : Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
+ OutputFile(Other.OutputFile) {}
+
+ Command &operator=(const Command &Other) {
+ Args = Other.Args;
+ CombinedOutAndErr = Other.CombinedOutAndErr;
+ OutputFile = Other.OutputFile;
+ return *this;
+ }
+
+ ~Command() {}
+
+ // Returns true if the given Arg is present in Args. Only checks up to
+ // "-ignore_remaining_args=1".
+ bool hasArgument(const std::string &Arg) const {
+ auto i = endMutableArgs();
+ return std::find(Args.begin(), i, Arg) != i;
+ }
+
+ // Gets all of the current command line arguments, **including** those after
+ // "-ignore-remaining-args=1".
+ const Vector<std::string> &getArguments() const { return Args; }
+
+ // Adds the given argument before "-ignore_remaining_args=1", or at the end
+ // if that flag isn't present.
+ void addArgument(const std::string &Arg) {
+ Args.insert(endMutableArgs(), Arg);
+ }
+
+ // Adds all given arguments before "-ignore_remaining_args=1", or at the end
+ // if that flag isn't present.
+ void addArguments(const Vector<std::string> &ArgsToAdd) {
+ Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
+ }
+
+ // Removes the given argument from the command argument list. Ignores any
+ // occurrences after "-ignore_remaining_args=1", if present.
+ void removeArgument(const std::string &Arg) {
+ auto i = endMutableArgs();
+ Args.erase(std::remove(Args.begin(), i, Arg), i);
+ }
+
+ // Like hasArgument, but checks for "-[Flag]=...".
+ bool hasFlag(const std::string &Flag) {
+ std::string Arg("-" + Flag + "=");
+ auto IsMatch = [&](const std::string &Other) {
+ return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+ };
+ return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
+ }
+
+ // Returns the value of the first instance of a given flag, or an empty string
+ // if the flag isn't present. Ignores any occurrences after
+ // "-ignore_remaining_args=1", if present.
+ std::string getFlagValue(const std::string &Flag) {
+ std::string Arg("-" + Flag + "=");
+ auto IsMatch = [&](const std::string &Other) {
+ return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+ };
+ auto i = endMutableArgs();
+ auto j = std::find_if(Args.begin(), i, IsMatch);
+ std::string result;
+ if (j != i) {
+ result = j->substr(Arg.length());
+ }
+ return result;
+ }
+
+ // Like AddArgument, but adds "-[Flag]=[Value]".
+ void addFlag(const std::string &Flag, const std::string &Value) {
+ addArgument("-" + Flag + "=" + Value);
+ }
+
+ // Like RemoveArgument, but removes "-[Flag]=...".
+ void removeFlag(const std::string &Flag) {
+ std::string Arg("-" + Flag + "=");
+ auto IsMatch = [&](const std::string &Other) {
+ return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+ };
+ auto i = endMutableArgs();
+ Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
+ }
+
+ // Returns whether the command's stdout is being written to an output file.
+ bool hasOutputFile() const { return !OutputFile.empty(); }
+
+ // Returns the currently set output file.
+ const std::string &getOutputFile() const { return OutputFile; }
+
+ // Configures the command to redirect its output to the name file.
+ void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
+
+ // Returns whether the command's stderr is redirected to stdout.
+ bool isOutAndErrCombined() const { return CombinedOutAndErr; }
+
+ // Sets whether to redirect the command's stderr to its stdout.
+ void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }
+
+ // Returns a string representation of the command. On many systems this will
+ // be the equivalent command line.
+ std::string toString() const {
+ std::stringstream SS;
+ for (auto arg : getArguments())
+ SS << arg << " ";
+ if (hasOutputFile())
+ SS << ">" << getOutputFile() << " ";
+ if (isOutAndErrCombined())
+ SS << "2>&1 ";
+ std::string result = SS.str();
+ if (!result.empty())
+ result = result.substr(0, result.length() - 1);
+ return result;
+ }
+
+private:
+ Command(Command &&Other) = delete;
+ Command &operator=(Command &&Other) = delete;
+
+ Vector<std::string>::iterator endMutableArgs() {
+ return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
+ }
+
+ Vector<std::string>::const_iterator endMutableArgs() const {
+ return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
+ }
+
+ // The command arguments. Args[0] is the command name.
+ Vector<std::string> Args;
+
+ // True indicates stderr is redirected to stdout.
+ bool CombinedOutAndErr;
+
+ // If not empty, stdout is redirected to the named file.
+ std::string OutputFile;
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_COMMAND_H
diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h
new file mode 100644
index 000000000000..2da929835f45
--- /dev/null
+++ b/lib/fuzzer/FuzzerCorpus.h
@@ -0,0 +1,302 @@
+//===- FuzzerCorpus.h - Internal header for the Fuzzer ----------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::InputCorpus
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_CORPUS
+#define LLVM_FUZZER_CORPUS
+
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+#include "FuzzerRandom.h"
+#include "FuzzerSHA1.h"
+#include "FuzzerTracePC.h"
+#include <algorithm>
+#include <numeric>
+#include <random>
+#include <unordered_set>
+
+namespace fuzzer {
+
+struct InputInfo {
+ Unit U; // The actual input data.
+ uint8_t Sha1[kSHA1NumBytes]; // Checksum.
+ // Number of features that this input has and no smaller input has.
+ size_t NumFeatures = 0;
+ size_t Tmp = 0; // Used by ValidateFeatureSet.
+ // Stats.
+ size_t NumExecutedMutations = 0;
+ size_t NumSuccessfullMutations = 0;
+ bool MayDeleteFile = false;
+ bool Reduced = false;
+ Vector<uint32_t> UniqFeatureSet;
+ float FeatureFrequencyScore = 1.0;
+};
+
+class InputCorpus {
+ static const size_t kFeatureSetSize = 1 << 21;
+ public:
+ InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) {
+ memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
+ memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
+ memset(FeatureFrequency, 0, sizeof(FeatureFrequency));
+ }
+ ~InputCorpus() {
+ for (auto II : Inputs)
+ delete II;
+ }
+ size_t size() const { return Inputs.size(); }
+ size_t SizeInBytes() const {
+ size_t Res = 0;
+ for (auto II : Inputs)
+ Res += II->U.size();
+ return Res;
+ }
+ size_t NumActiveUnits() const {
+ size_t Res = 0;
+ for (auto II : Inputs)
+ Res += !II->U.empty();
+ return Res;
+ }
+ size_t MaxInputSize() const {
+ size_t Res = 0;
+ for (auto II : Inputs)
+ Res = std::max(Res, II->U.size());
+ return Res;
+ }
+ bool empty() const { return Inputs.empty(); }
+ const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
+ void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile,
+ const Vector<uint32_t> &FeatureSet) {
+ assert(!U.empty());
+ if (FeatureDebug)
+ Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
+ Inputs.push_back(new InputInfo());
+ InputInfo &II = *Inputs.back();
+ II.U = U;
+ II.NumFeatures = NumFeatures;
+ II.MayDeleteFile = MayDeleteFile;
+ II.UniqFeatureSet = FeatureSet;
+ std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());
+ ComputeSHA1(U.data(), U.size(), II.Sha1);
+ Hashes.insert(Sha1ToString(II.Sha1));
+ UpdateCorpusDistribution();
+ PrintCorpus();
+ // ValidateFeatureSet();
+ }
+
+ // Debug-only
+ void PrintUnit(const Unit &U) {
+ if (!FeatureDebug) return;
+ for (uint8_t C : U) {
+ if (C != 'F' && C != 'U' && C != 'Z')
+ C = '.';
+ Printf("%c", C);
+ }
+ }
+
+ // Debug-only
+ void PrintFeatureSet(const Vector<uint32_t> &FeatureSet) {
+ if (!FeatureDebug) return;
+ Printf("{");
+ for (uint32_t Feature: FeatureSet)
+ Printf("%u,", Feature);
+ Printf("}");
+ }
+
+ // Debug-only
+ void PrintCorpus() {
+ if (!FeatureDebug) return;
+ Printf("======= CORPUS:\n");
+ int i = 0;
+ for (auto II : Inputs) {
+ if (std::find(II->U.begin(), II->U.end(), 'F') != II->U.end()) {
+ Printf("[%2d] ", i);
+ Printf("%s sz=%zd ", Sha1ToString(II->Sha1).c_str(), II->U.size());
+ PrintUnit(II->U);
+ Printf(" ");
+ PrintFeatureSet(II->UniqFeatureSet);
+ Printf("\n");
+ }
+ i++;
+ }
+ }
+
+ void Replace(InputInfo *II, const Unit &U) {
+ assert(II->U.size() > U.size());
+ Hashes.erase(Sha1ToString(II->Sha1));
+ DeleteFile(*II);
+ ComputeSHA1(U.data(), U.size(), II->Sha1);
+ Hashes.insert(Sha1ToString(II->Sha1));
+ II->U = U;
+ II->Reduced = true;
+ UpdateCorpusDistribution();
+ }
+
+ bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
+ bool HasUnit(const std::string &H) { return Hashes.count(H); }
+ InputInfo &ChooseUnitToMutate(Random &Rand) {
+ InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)];
+ assert(!II.U.empty());
+ return II;
+ };
+
+ // Returns an index of random unit from the corpus to mutate.
+ size_t ChooseUnitIdxToMutate(Random &Rand) {
+ size_t Idx = static_cast<size_t>(CorpusDistribution(Rand));
+ assert(Idx < Inputs.size());
+ return Idx;
+ }
+
+ void PrintStats() {
+ for (size_t i = 0; i < Inputs.size(); i++) {
+ const auto &II = *Inputs[i];
+ Printf(" [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i,
+ Sha1ToString(II.Sha1).c_str(), II.U.size(),
+ II.NumExecutedMutations, II.NumSuccessfullMutations);
+ }
+ }
+
+ void PrintFeatureSet() {
+ for (size_t i = 0; i < kFeatureSetSize; i++) {
+ if(size_t Sz = GetFeature(i))
+ Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz);
+ }
+ Printf("\n\t");
+ for (size_t i = 0; i < Inputs.size(); i++)
+ if (size_t N = Inputs[i]->NumFeatures)
+ Printf(" %zd=>%zd ", i, N);
+ Printf("\n");
+ }
+
+ void DeleteFile(const InputInfo &II) {
+ if (!OutputCorpus.empty() && II.MayDeleteFile)
+ RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1)));
+ }
+
+ void DeleteInput(size_t Idx) {
+ InputInfo &II = *Inputs[Idx];
+ DeleteFile(II);
+ Unit().swap(II.U);
+ if (FeatureDebug)
+ Printf("EVICTED %zd\n", Idx);
+ }
+
+ bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
+ assert(NewSize);
+ Idx = Idx % kFeatureSetSize;
+ uint32_t OldSize = GetFeature(Idx);
+ if (OldSize == 0 || (Shrink && OldSize > NewSize)) {
+ if (OldSize > 0) {
+ size_t OldIdx = SmallestElementPerFeature[Idx];
+ InputInfo &II = *Inputs[OldIdx];
+ assert(II.NumFeatures > 0);
+ II.NumFeatures--;
+ if (II.NumFeatures == 0)
+ DeleteInput(OldIdx);
+ } else {
+ NumAddedFeatures++;
+ }
+ NumUpdatedFeatures++;
+ if (FeatureDebug)
+ Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize);
+ SmallestElementPerFeature[Idx] = Inputs.size();
+ InputSizesPerFeature[Idx] = NewSize;
+ return true;
+ }
+ return false;
+ }
+
+ void UpdateFeatureFrequency(size_t Idx) {
+ FeatureFrequency[Idx % kFeatureSetSize]++;
+ }
+ float GetFeatureFrequency(size_t Idx) const {
+ return FeatureFrequency[Idx % kFeatureSetSize];
+ }
+ void UpdateFeatureFrequencyScore(InputInfo *II) {
+ const float kMin = 0.01, kMax = 100.;
+ II->FeatureFrequencyScore = kMin;
+ for (auto Idx : II->UniqFeatureSet)
+ II->FeatureFrequencyScore += 1. / (GetFeatureFrequency(Idx) + 1.);
+ II->FeatureFrequencyScore = Min(II->FeatureFrequencyScore, kMax);
+ }
+
+ size_t NumFeatures() const { return NumAddedFeatures; }
+ size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
+
+private:
+
+ static const bool FeatureDebug = false;
+
+ size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; }
+
+ void ValidateFeatureSet() {
+ if (FeatureDebug)
+ PrintFeatureSet();
+ for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++)
+ if (GetFeature(Idx))
+ Inputs[SmallestElementPerFeature[Idx]]->Tmp++;
+ for (auto II: Inputs) {
+ if (II->Tmp != II->NumFeatures)
+ Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures);
+ assert(II->Tmp == II->NumFeatures);
+ II->Tmp = 0;
+ }
+ }
+
+ // Updates the probability distribution for the units in the corpus.
+ // Must be called whenever the corpus or unit weights are changed.
+ //
+ // Hypothesis: units added to the corpus last are more interesting.
+ //
+ // Hypothesis: inputs with infrequent features are more interesting.
+ void UpdateCorpusDistribution() {
+ size_t N = Inputs.size();
+ assert(N);
+ Intervals.resize(N + 1);
+ Weights.resize(N);
+ std::iota(Intervals.begin(), Intervals.end(), 0);
+ for (size_t i = 0; i < N; i++)
+ Weights[i] = Inputs[i]->NumFeatures
+ ? (i + 1) * Inputs[i]->FeatureFrequencyScore
+ : 0.;
+ if (FeatureDebug) {
+ for (size_t i = 0; i < N; i++)
+ Printf("%zd ", Inputs[i]->NumFeatures);
+ Printf("NUM\n");
+ for (size_t i = 0; i < N; i++)
+ Printf("%f ", Inputs[i]->FeatureFrequencyScore);
+ Printf("SCORE\n");
+ for (size_t i = 0; i < N; i++)
+ Printf("%f ", Weights[i]);
+ Printf("Weights\n");
+ }
+ CorpusDistribution = std::piecewise_constant_distribution<double>(
+ Intervals.begin(), Intervals.end(), Weights.begin());
+ }
+ std::piecewise_constant_distribution<double> CorpusDistribution;
+
+ Vector<double> Intervals;
+ Vector<double> Weights;
+
+ std::unordered_set<std::string> Hashes;
+ Vector<InputInfo*> Inputs;
+
+ size_t NumAddedFeatures = 0;
+ size_t NumUpdatedFeatures = 0;
+ uint32_t InputSizesPerFeature[kFeatureSetSize];
+ uint32_t SmallestElementPerFeature[kFeatureSetSize];
+ float FeatureFrequency[kFeatureSetSize];
+
+ std::string OutputCorpus;
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_CORPUS
diff --git a/lib/fuzzer/FuzzerCrossOver.cpp b/lib/fuzzer/FuzzerCrossOver.cpp
new file mode 100644
index 000000000000..8b0fd7d529a8
--- /dev/null
+++ b/lib/fuzzer/FuzzerCrossOver.cpp
@@ -0,0 +1,52 @@
+//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Cross over test inputs.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDefs.h"
+#include "FuzzerMutate.h"
+#include "FuzzerRandom.h"
+#include <cstring>
+
+namespace fuzzer {
+
+// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
+size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1,
+ const uint8_t *Data2, size_t Size2,
+ uint8_t *Out, size_t MaxOutSize) {
+ assert(Size1 || Size2);
+ MaxOutSize = Rand(MaxOutSize) + 1;
+ size_t OutPos = 0;
+ size_t Pos1 = 0;
+ size_t Pos2 = 0;
+ size_t *InPos = &Pos1;
+ size_t InSize = Size1;
+ const uint8_t *Data = Data1;
+ bool CurrentlyUsingFirstData = true;
+ while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) {
+ // Merge a part of Data into Out.
+ size_t OutSizeLeft = MaxOutSize - OutPos;
+ if (*InPos < InSize) {
+ size_t InSizeLeft = InSize - *InPos;
+ size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft);
+ size_t ExtraSize = Rand(MaxExtraSize) + 1;
+ memcpy(Out + OutPos, Data + *InPos, ExtraSize);
+ OutPos += ExtraSize;
+ (*InPos) += ExtraSize;
+ }
+ // Use the other input data on the next iteration.
+ InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1;
+ InSize = CurrentlyUsingFirstData ? Size2 : Size1;
+ Data = CurrentlyUsingFirstData ? Data2 : Data1;
+ CurrentlyUsingFirstData = !CurrentlyUsingFirstData;
+ }
+ return OutPos;
+}
+
+} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h
new file mode 100644
index 000000000000..5942efc47a4a
--- /dev/null
+++ b/lib/fuzzer/FuzzerDefs.h
@@ -0,0 +1,167 @@
+//===- FuzzerDefs.h - Internal header for the Fuzzer ------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Basic definitions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_DEFS_H
+#define LLVM_FUZZER_DEFS_H
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <vector>
+#include <set>
+#include <memory>
+
+// Platform detection.
+#ifdef __linux__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 1
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_WINDOWS 0
+#elif __APPLE__
+#define LIBFUZZER_APPLE 1
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_WINDOWS 0
+#elif __NetBSD__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 1
+#define LIBFUZZER_WINDOWS 0
+#elif _WIN32
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_WINDOWS 1
+#elif __Fuchsia__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 1
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_WINDOWS 0
+#else
+#error "Support for your platform has not been implemented"
+#endif
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0
+#endif
+
+#define LIBFUZZER_POSIX (LIBFUZZER_APPLE || LIBFUZZER_LINUX || LIBFUZZER_NETBSD)
+
+#ifdef __x86_64
+# if __has_attribute(target)
+# define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt")))
+# else
+# define ATTRIBUTE_TARGET_POPCNT
+# endif
+#else
+# define ATTRIBUTE_TARGET_POPCNT
+#endif
+
+
+#ifdef __clang__ // avoid gcc warning.
+# if __has_attribute(no_sanitize)
+# define ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
+# else
+# define ATTRIBUTE_NO_SANITIZE_MEMORY
+# endif
+# define ALWAYS_INLINE __attribute__((always_inline))
+#else
+# define ATTRIBUTE_NO_SANITIZE_MEMORY
+# define ALWAYS_INLINE
+#endif // __clang__
+
+#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+
+#if defined(__has_feature)
+# if __has_feature(address_sanitizer)
+# define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_ADDRESS
+# elif __has_feature(memory_sanitizer)
+# define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_MEMORY
+# else
+# define ATTRIBUTE_NO_SANITIZE_ALL
+# endif
+#else
+# define ATTRIBUTE_NO_SANITIZE_ALL
+#endif
+
+#if LIBFUZZER_WINDOWS
+#define ATTRIBUTE_INTERFACE __declspec(dllexport)
+#else
+#define ATTRIBUTE_INTERFACE __attribute__((visibility("default")))
+#endif
+
+namespace fuzzer {
+
+template <class T> T Min(T a, T b) { return a < b ? a : b; }
+template <class T> T Max(T a, T b) { return a > b ? a : b; }
+
+class Random;
+class Dictionary;
+class DictionaryEntry;
+class MutationDispatcher;
+struct FuzzingOptions;
+class InputCorpus;
+struct InputInfo;
+struct ExternalFunctions;
+
+// Global interface to functions that may or may not be available.
+extern ExternalFunctions *EF;
+
+// We are using a custom allocator to give a different symbol name to STL
+// containers in order to avoid ODR violations.
+template<typename T>
+ class fuzzer_allocator: public std::allocator<T> {
+ public:
+ template<class Other>
+ struct rebind { typedef fuzzer_allocator<Other> other; };
+ };
+
+template<typename T>
+using Vector = std::vector<T, fuzzer_allocator<T>>;
+
+template<typename T>
+using Set = std::set<T, std::less<T>, fuzzer_allocator<T>>;
+
+typedef Vector<uint8_t> Unit;
+typedef Vector<Unit> UnitVector;
+typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
+
+int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
+
+struct ScopedDoingMyOwnMemOrStr {
+ ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr++; }
+ ~ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr--; }
+ static int DoingMyOwnMemOrStr;
+};
+
+inline uint8_t Bswap(uint8_t x) { return x; }
+inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
+inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
+inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
+
+uint8_t *ExtraCountersBegin();
+uint8_t *ExtraCountersEnd();
+void ClearExtraCounters();
+
+uint64_t *ClangCountersBegin();
+uint64_t *ClangCountersEnd();
+void ClearClangCounters();
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_DEFS_H
diff --git a/lib/fuzzer/FuzzerDictionary.h b/lib/fuzzer/FuzzerDictionary.h
new file mode 100644
index 000000000000..daf7d003ea91
--- /dev/null
+++ b/lib/fuzzer/FuzzerDictionary.h
@@ -0,0 +1,127 @@
+//===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::Dictionary
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_DICTIONARY_H
+#define LLVM_FUZZER_DICTIONARY_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+#include "FuzzerUtil.h"
+#include <algorithm>
+#include <limits>
+
+namespace fuzzer {
+// A simple POD sized array of bytes.
+template <size_t kMaxSizeT> class FixedWord {
+public:
+ static const size_t kMaxSize = kMaxSizeT;
+ FixedWord() {}
+ FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); }
+
+ void Set(const uint8_t *B, uint8_t S) {
+ assert(S <= kMaxSize);
+ memcpy(Data, B, S);
+ Size = S;
+ }
+
+ bool operator==(const FixedWord<kMaxSize> &w) const {
+ ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str;
+ return Size == w.Size && 0 == memcmp(Data, w.Data, Size);
+ }
+
+ bool operator<(const FixedWord<kMaxSize> &w) const {
+ ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str;
+ if (Size != w.Size)
+ return Size < w.Size;
+ return memcmp(Data, w.Data, Size) < 0;
+ }
+
+ static size_t GetMaxSize() { return kMaxSize; }
+ const uint8_t *data() const { return Data; }
+ uint8_t size() const { return Size; }
+
+private:
+ uint8_t Size = 0;
+ uint8_t Data[kMaxSize];
+};
+
+typedef FixedWord<64> Word;
+
+class DictionaryEntry {
+ public:
+ DictionaryEntry() {}
+ DictionaryEntry(Word W) : W(W) {}
+ DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
+ const Word &GetW() const { return W; }
+
+ bool HasPositionHint() const { return PositionHint != std::numeric_limits<size_t>::max(); }
+ size_t GetPositionHint() const {
+ assert(HasPositionHint());
+ return PositionHint;
+ }
+ void IncUseCount() { UseCount++; }
+ void IncSuccessCount() { SuccessCount++; }
+ size_t GetUseCount() const { return UseCount; }
+ size_t GetSuccessCount() const {return SuccessCount; }
+
+ void Print(const char *PrintAfter = "\n") {
+ PrintASCII(W.data(), W.size());
+ if (HasPositionHint())
+ Printf("@%zd", GetPositionHint());
+ Printf("%s", PrintAfter);
+ }
+
+private:
+ Word W;
+ size_t PositionHint = std::numeric_limits<size_t>::max();
+ size_t UseCount = 0;
+ size_t SuccessCount = 0;
+};
+
+class Dictionary {
+ public:
+ static const size_t kMaxDictSize = 1 << 14;
+
+ bool ContainsWord(const Word &W) const {
+ return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) {
+ return DE.GetW() == W;
+ });
+ }
+ const DictionaryEntry *begin() const { return &DE[0]; }
+ const DictionaryEntry *end() const { return begin() + Size; }
+ DictionaryEntry & operator[] (size_t Idx) {
+ assert(Idx < Size);
+ return DE[Idx];
+ }
+ void push_back(DictionaryEntry DE) {
+ if (Size < kMaxDictSize)
+ this->DE[Size++] = DE;
+ }
+ void clear() { Size = 0; }
+ bool empty() const { return Size == 0; }
+ size_t size() const { return Size; }
+
+private:
+ DictionaryEntry DE[kMaxDictSize];
+ size_t Size = 0;
+};
+
+// Parses one dictionary entry.
+// If successfull, write the enty to Unit and returns true,
+// otherwise returns false.
+bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
+// Parses the dictionary file, fills Units, returns true iff all lines
+// were parsed succesfully.
+bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units);
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_DICTIONARY_H
diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp
new file mode 100644
index 000000000000..f6b642daeda7
--- /dev/null
+++ b/lib/fuzzer/FuzzerDriver.cpp
@@ -0,0 +1,767 @@
+//===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// FuzzerDriver and flag parsing.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerCommand.h"
+#include "FuzzerCorpus.h"
+#include "FuzzerIO.h"
+#include "FuzzerInterface.h"
+#include "FuzzerInternal.h"
+#include "FuzzerMutate.h"
+#include "FuzzerRandom.h"
+#include "FuzzerShmem.h"
+#include "FuzzerTracePC.h"
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <cstdlib>
+#include <cstring>
+#include <mutex>
+#include <string>
+#include <thread>
+
+// This function should be present in the libFuzzer so that the client
+// binary can test for its existence.
+extern "C" __attribute__((used)) void __libfuzzer_is_present() {}
+
+namespace fuzzer {
+
+// Program arguments.
+struct FlagDescription {
+ const char *Name;
+ const char *Description;
+ int Default;
+ int *IntFlag;
+ const char **StrFlag;
+ unsigned int *UIntFlag;
+};
+
+struct {
+#define FUZZER_DEPRECATED_FLAG(Name)
+#define FUZZER_FLAG_INT(Name, Default, Description) int Name;
+#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
+#define FUZZER_FLAG_STRING(Name, Description) const char *Name;
+#include "FuzzerFlags.def"
+#undef FUZZER_DEPRECATED_FLAG
+#undef FUZZER_FLAG_INT
+#undef FUZZER_FLAG_UNSIGNED
+#undef FUZZER_FLAG_STRING
+} Flags;
+
+static const FlagDescription FlagDescriptions [] {
+#define FUZZER_DEPRECATED_FLAG(Name) \
+ {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr},
+#define FUZZER_FLAG_INT(Name, Default, Description) \
+ {#Name, Description, Default, &Flags.Name, nullptr, nullptr},
+#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \
+ {#Name, Description, static_cast<int>(Default), \
+ nullptr, nullptr, &Flags.Name},
+#define FUZZER_FLAG_STRING(Name, Description) \
+ {#Name, Description, 0, nullptr, &Flags.Name, nullptr},
+#include "FuzzerFlags.def"
+#undef FUZZER_DEPRECATED_FLAG
+#undef FUZZER_FLAG_INT
+#undef FUZZER_FLAG_UNSIGNED
+#undef FUZZER_FLAG_STRING
+};
+
+static const size_t kNumFlags =
+ sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
+
+static Vector<std::string> *Inputs;
+static std::string *ProgName;
+
+static void PrintHelp() {
+ Printf("Usage:\n");
+ auto Prog = ProgName->c_str();
+ Printf("\nTo run fuzzing pass 0 or more directories.\n");
+ Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog);
+
+ Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n");
+ Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog);
+
+ Printf("\nFlags: (strictly in form -flag=value)\n");
+ size_t MaxFlagLen = 0;
+ for (size_t F = 0; F < kNumFlags; F++)
+ MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
+
+ for (size_t F = 0; F < kNumFlags; F++) {
+ const auto &D = FlagDescriptions[F];
+ if (strstr(D.Description, "internal flag") == D.Description) continue;
+ Printf(" %s", D.Name);
+ for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
+ Printf(" ");
+ Printf("\t");
+ Printf("%d\t%s\n", D.Default, D.Description);
+ }
+ Printf("\nFlags starting with '--' will be ignored and "
+ "will be passed verbatim to subprocesses.\n");
+}
+
+static const char *FlagValue(const char *Param, const char *Name) {
+ size_t Len = strlen(Name);
+ if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
+ Param[Len + 1] == '=')
+ return &Param[Len + 2];
+ return nullptr;
+}
+
+// Avoid calling stol as it triggers a bug in clang/glibc build.
+static long MyStol(const char *Str) {
+ long Res = 0;
+ long Sign = 1;
+ if (*Str == '-') {
+ Str++;
+ Sign = -1;
+ }
+ for (size_t i = 0; Str[i]; i++) {
+ char Ch = Str[i];
+ if (Ch < '0' || Ch > '9')
+ return Res;
+ Res = Res * 10 + (Ch - '0');
+ }
+ return Res * Sign;
+}
+
+static bool ParseOneFlag(const char *Param) {
+ if (Param[0] != '-') return false;
+ if (Param[1] == '-') {
+ static bool PrintedWarning = false;
+ if (!PrintedWarning) {
+ PrintedWarning = true;
+ Printf("INFO: libFuzzer ignores flags that start with '--'\n");
+ }
+ for (size_t F = 0; F < kNumFlags; F++)
+ if (FlagValue(Param + 1, FlagDescriptions[F].Name))
+ Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1);
+ return true;
+ }
+ for (size_t F = 0; F < kNumFlags; F++) {
+ const char *Name = FlagDescriptions[F].Name;
+ const char *Str = FlagValue(Param, Name);
+ if (Str) {
+ if (FlagDescriptions[F].IntFlag) {
+ int Val = MyStol(Str);
+ *FlagDescriptions[F].IntFlag = Val;
+ if (Flags.verbosity >= 2)
+ Printf("Flag: %s %d\n", Name, Val);
+ return true;
+ } else if (FlagDescriptions[F].UIntFlag) {
+ unsigned int Val = std::stoul(Str);
+ *FlagDescriptions[F].UIntFlag = Val;
+ if (Flags.verbosity >= 2)
+ Printf("Flag: %s %u\n", Name, Val);
+ return true;
+ } else if (FlagDescriptions[F].StrFlag) {
+ *FlagDescriptions[F].StrFlag = Str;
+ if (Flags.verbosity >= 2)
+ Printf("Flag: %s %s\n", Name, Str);
+ return true;
+ } else { // Deprecated flag.
+ Printf("Flag: %s: deprecated, don't use\n", Name);
+ return true;
+ }
+ }
+ }
+ Printf("\n\nWARNING: unrecognized flag '%s'; "
+ "use -help=1 to list all flags\n\n", Param);
+ return true;
+}
+
+// We don't use any library to minimize dependencies.
+static void ParseFlags(const Vector<std::string> &Args) {
+ for (size_t F = 0; F < kNumFlags; F++) {
+ if (FlagDescriptions[F].IntFlag)
+ *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
+ if (FlagDescriptions[F].UIntFlag)
+ *FlagDescriptions[F].UIntFlag =
+ static_cast<unsigned int>(FlagDescriptions[F].Default);
+ if (FlagDescriptions[F].StrFlag)
+ *FlagDescriptions[F].StrFlag = nullptr;
+ }
+ Inputs = new Vector<std::string>;
+ for (size_t A = 1; A < Args.size(); A++) {
+ if (ParseOneFlag(Args[A].c_str())) {
+ if (Flags.ignore_remaining_args)
+ break;
+ continue;
+ }
+ Inputs->push_back(Args[A]);
+ }
+}
+
+static std::mutex Mu;
+
+static void PulseThread() {
+ while (true) {
+ SleepSeconds(600);
+ std::lock_guard<std::mutex> Lock(Mu);
+ Printf("pulse...\n");
+ }
+}
+
+static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter,
+ unsigned NumJobs, std::atomic<bool> *HasErrors) {
+ while (true) {
+ unsigned C = (*Counter)++;
+ if (C >= NumJobs) break;
+ std::string Log = "fuzz-" + std::to_string(C) + ".log";
+ Command Cmd(BaseCmd);
+ Cmd.setOutputFile(Log);
+ Cmd.combineOutAndErr();
+ if (Flags.verbosity) {
+ std::string CommandLine = Cmd.toString();
+ Printf("%s\n", CommandLine.c_str());
+ }
+ int ExitCode = ExecuteCommand(Cmd);
+ if (ExitCode != 0)
+ *HasErrors = true;
+ std::lock_guard<std::mutex> Lock(Mu);
+ Printf("================== Job %u exited with exit code %d ============\n",
+ C, ExitCode);
+ fuzzer::CopyFileToErr(Log);
+ }
+}
+
+std::string CloneArgsWithoutX(const Vector<std::string> &Args,
+ const char *X1, const char *X2) {
+ std::string Cmd;
+ for (auto &S : Args) {
+ if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
+ continue;
+ Cmd += S + " ";
+ }
+ return Cmd;
+}
+
+static int RunInMultipleProcesses(const Vector<std::string> &Args,
+ unsigned NumWorkers, unsigned NumJobs) {
+ std::atomic<unsigned> Counter(0);
+ std::atomic<bool> HasErrors(false);
+ Command Cmd(Args);
+ Cmd.removeFlag("jobs");
+ Cmd.removeFlag("workers");
+ Vector<std::thread> V;
+ std::thread Pulse(PulseThread);
+ Pulse.detach();
+ for (unsigned i = 0; i < NumWorkers; i++)
+ V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, &HasErrors));
+ for (auto &T : V)
+ T.join();
+ return HasErrors ? 1 : 0;
+}
+
+static void RssThread(Fuzzer *F, size_t RssLimitMb) {
+ while (true) {
+ SleepSeconds(1);
+ size_t Peak = GetPeakRSSMb();
+ if (Peak > RssLimitMb)
+ F->RssLimitCallback();
+ }
+}
+
+static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
+ if (!RssLimitMb) return;
+ std::thread T(RssThread, F, RssLimitMb);
+ T.detach();
+}
+
+int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
+ Unit U = FileToVector(InputFilePath);
+ if (MaxLen && MaxLen < U.size())
+ U.resize(MaxLen);
+ F->ExecuteCallback(U.data(), U.size());
+ F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
+ return 0;
+}
+
+static bool AllInputsAreFiles() {
+ if (Inputs->empty()) return false;
+ for (auto &Path : *Inputs)
+ if (!IsFile(Path))
+ return false;
+ return true;
+}
+
+static std::string GetDedupTokenFromFile(const std::string &Path) {
+ auto S = FileToString(Path);
+ auto Beg = S.find("DEDUP_TOKEN:");
+ if (Beg == std::string::npos)
+ return "";
+ auto End = S.find('\n', Beg);
+ if (End == std::string::npos)
+ return "";
+ return S.substr(Beg, End - Beg);
+}
+
+int CleanseCrashInput(const Vector<std::string> &Args,
+ const FuzzingOptions &Options) {
+ if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
+ Printf("ERROR: -cleanse_crash should be given one input file and"
+ " -exact_artifact_path\n");
+ exit(1);
+ }
+ std::string InputFilePath = Inputs->at(0);
+ std::string OutputFilePath = Flags.exact_artifact_path;
+ Command Cmd(Args);
+ Cmd.removeFlag("cleanse_crash");
+
+ assert(Cmd.hasArgument(InputFilePath));
+ Cmd.removeArgument(InputFilePath);
+
+ auto LogFilePath = DirPlusFile(
+ TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
+ auto TmpFilePath = DirPlusFile(
+ TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro");
+ Cmd.addArgument(TmpFilePath);
+ Cmd.setOutputFile(LogFilePath);
+ Cmd.combineOutAndErr();
+
+ std::string CurrentFilePath = InputFilePath;
+ auto U = FileToVector(CurrentFilePath);
+ size_t Size = U.size();
+
+ const Vector<uint8_t> ReplacementBytes = {' ', 0xff};
+ for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
+ bool Changed = false;
+ for (size_t Idx = 0; Idx < Size; Idx++) {
+ Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts,
+ Idx, Size);
+ uint8_t OriginalByte = U[Idx];
+ if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(),
+ ReplacementBytes.end(),
+ OriginalByte))
+ continue;
+ for (auto NewByte : ReplacementBytes) {
+ U[Idx] = NewByte;
+ WriteToFile(U, TmpFilePath);
+ auto ExitCode = ExecuteCommand(Cmd);
+ RemoveFile(TmpFilePath);
+ if (!ExitCode) {
+ U[Idx] = OriginalByte;
+ } else {
+ Changed = true;
+ Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte);
+ WriteToFile(U, OutputFilePath);
+ break;
+ }
+ }
+ }
+ if (!Changed) break;
+ }
+ RemoveFile(LogFilePath);
+ return 0;
+}
+
+int MinimizeCrashInput(const Vector<std::string> &Args,
+ const FuzzingOptions &Options) {
+ if (Inputs->size() != 1) {
+ Printf("ERROR: -minimize_crash should be given one input file\n");
+ exit(1);
+ }
+ std::string InputFilePath = Inputs->at(0);
+ Command BaseCmd(Args);
+ BaseCmd.removeFlag("minimize_crash");
+ BaseCmd.removeFlag("exact_artifact_path");
+ assert(BaseCmd.hasArgument(InputFilePath));
+ BaseCmd.removeArgument(InputFilePath);
+ if (Flags.runs <= 0 && Flags.max_total_time == 0) {
+ Printf("INFO: you need to specify -runs=N or "
+ "-max_total_time=N with -minimize_crash=1\n"
+ "INFO: defaulting to -max_total_time=600\n");
+ BaseCmd.addFlag("max_total_time", "600");
+ }
+
+ auto LogFilePath = DirPlusFile(
+ TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
+ BaseCmd.setOutputFile(LogFilePath);
+ BaseCmd.combineOutAndErr();
+
+ std::string CurrentFilePath = InputFilePath;
+ while (true) {
+ Unit U = FileToVector(CurrentFilePath);
+ Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
+ CurrentFilePath.c_str(), U.size());
+
+ Command Cmd(BaseCmd);
+ Cmd.addArgument(CurrentFilePath);
+
+ std::string CommandLine = Cmd.toString();
+ Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str());
+ int ExitCode = ExecuteCommand(Cmd);
+ if (ExitCode == 0) {
+ Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
+ exit(1);
+ }
+ Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
+ "it further\n",
+ CurrentFilePath.c_str(), U.size());
+ auto DedupToken1 = GetDedupTokenFromFile(LogFilePath);
+ if (!DedupToken1.empty())
+ Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str());
+
+ std::string ArtifactPath =
+ Flags.exact_artifact_path
+ ? Flags.exact_artifact_path
+ : Options.ArtifactPrefix + "minimized-from-" + Hash(U);
+ Cmd.addFlag("minimize_crash_internal_step", "1");
+ Cmd.addFlag("exact_artifact_path", ArtifactPath);
+ CommandLine = Cmd.toString();
+ Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str());
+ ExitCode = ExecuteCommand(Cmd);
+ CopyFileToErr(LogFilePath);
+ if (ExitCode == 0) {
+ if (Flags.exact_artifact_path) {
+ CurrentFilePath = Flags.exact_artifact_path;
+ WriteToFile(U, CurrentFilePath);
+ }
+ Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n",
+ CurrentFilePath.c_str(), U.size());
+ break;
+ }
+ auto DedupToken2 = GetDedupTokenFromFile(LogFilePath);
+ if (!DedupToken2.empty())
+ Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str());
+
+ if (DedupToken1 != DedupToken2) {
+ if (Flags.exact_artifact_path) {
+ CurrentFilePath = Flags.exact_artifact_path;
+ WriteToFile(U, CurrentFilePath);
+ }
+ Printf("CRASH_MIN: mismatch in dedup tokens"
+ " (looks like a different bug). Won't minimize further\n");
+ break;
+ }
+
+ CurrentFilePath = ArtifactPath;
+ Printf("*********************************\n");
+ }
+ RemoveFile(LogFilePath);
+ return 0;
+}
+
+int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
+ assert(Inputs->size() == 1);
+ std::string InputFilePath = Inputs->at(0);
+ Unit U = FileToVector(InputFilePath);
+ Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
+ if (U.size() < 2) {
+ Printf("INFO: The input is small enough, exiting\n");
+ exit(0);
+ }
+ F->SetMaxInputLen(U.size());
+ F->SetMaxMutationLen(U.size() - 1);
+ F->MinimizeCrashLoop(U);
+ Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
+ exit(0);
+ return 0;
+}
+
+int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict,
+ UnitVector& Corpus) {
+ Printf("Started dictionary minimization (up to %d tests)\n",
+ Dict.size() * Corpus.size() * 2);
+
+ // Scores and usage count for each dictionary unit.
+ Vector<int> Scores(Dict.size());
+ Vector<int> Usages(Dict.size());
+
+ Vector<size_t> InitialFeatures;
+ Vector<size_t> ModifiedFeatures;
+ for (auto &C : Corpus) {
+ // Get coverage for the testcase without modifications.
+ F->ExecuteCallback(C.data(), C.size());
+ InitialFeatures.clear();
+ TPC.CollectFeatures([&](size_t Feature) {
+ InitialFeatures.push_back(Feature);
+ });
+
+ for (size_t i = 0; i < Dict.size(); ++i) {
+ Vector<uint8_t> Data = C;
+ auto StartPos = std::search(Data.begin(), Data.end(),
+ Dict[i].begin(), Dict[i].end());
+ // Skip dictionary unit, if the testcase does not contain it.
+ if (StartPos == Data.end())
+ continue;
+
+ ++Usages[i];
+ while (StartPos != Data.end()) {
+ // Replace all occurrences of dictionary unit in the testcase.
+ auto EndPos = StartPos + Dict[i].size();
+ for (auto It = StartPos; It != EndPos; ++It)
+ *It ^= 0xFF;
+
+ StartPos = std::search(EndPos, Data.end(),
+ Dict[i].begin(), Dict[i].end());
+ }
+
+ // Get coverage for testcase with masked occurrences of dictionary unit.
+ F->ExecuteCallback(Data.data(), Data.size());
+ ModifiedFeatures.clear();
+ TPC.CollectFeatures([&](size_t Feature) {
+ ModifiedFeatures.push_back(Feature);
+ });
+
+ if (InitialFeatures == ModifiedFeatures)
+ --Scores[i];
+ else
+ Scores[i] += 2;
+ }
+ }
+
+ Printf("###### Useless dictionary elements. ######\n");
+ for (size_t i = 0; i < Dict.size(); ++i) {
+ // Dictionary units with positive score are treated as useful ones.
+ if (Scores[i] > 0)
+ continue;
+
+ Printf("\"");
+ PrintASCII(Dict[i].data(), Dict[i].size(), "\"");
+ Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]);
+ }
+ Printf("###### End of useless dictionary elements. ######\n");
+ return 0;
+}
+
+int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
+ using namespace fuzzer;
+ assert(argc && argv && "Argument pointers cannot be nullptr");
+ std::string Argv0((*argv)[0]);
+ EF = new ExternalFunctions();
+ if (EF->LLVMFuzzerInitialize)
+ EF->LLVMFuzzerInitialize(argc, argv);
+ const Vector<std::string> Args(*argv, *argv + *argc);
+ assert(!Args.empty());
+ ProgName = new std::string(Args[0]);
+ if (Argv0 != *ProgName) {
+ Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
+ exit(1);
+ }
+ ParseFlags(Args);
+ if (Flags.help) {
+ PrintHelp();
+ return 0;
+ }
+
+ if (Flags.close_fd_mask & 2)
+ DupAndCloseStderr();
+ if (Flags.close_fd_mask & 1)
+ CloseStdout();
+
+ if (Flags.jobs > 0 && Flags.workers == 0) {
+ Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
+ if (Flags.workers > 1)
+ Printf("Running %u workers\n", Flags.workers);
+ }
+
+ if (Flags.workers > 0 && Flags.jobs > 0)
+ return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
+
+ FuzzingOptions Options;
+ Options.Verbosity = Flags.verbosity;
+ Options.MaxLen = Flags.max_len;
+ Options.ExperimentalLenControl = Flags.experimental_len_control;
+ Options.UnitTimeoutSec = Flags.timeout;
+ Options.ErrorExitCode = Flags.error_exitcode;
+ Options.TimeoutExitCode = Flags.timeout_exitcode;
+ Options.MaxTotalTimeSec = Flags.max_total_time;
+ Options.DoCrossOver = Flags.cross_over;
+ Options.MutateDepth = Flags.mutate_depth;
+ Options.ReduceDepth = Flags.reduce_depth;
+ Options.UseCounters = Flags.use_counters;
+ Options.UseMemmem = Flags.use_memmem;
+ Options.UseCmp = Flags.use_cmp;
+ Options.UseValueProfile = Flags.use_value_profile;
+ Options.Shrink = Flags.shrink;
+ Options.ReduceInputs = Flags.reduce_inputs;
+ Options.ShuffleAtStartUp = Flags.shuffle;
+ Options.PreferSmall = Flags.prefer_small;
+ Options.ReloadIntervalSec = Flags.reload;
+ Options.OnlyASCII = Flags.only_ascii;
+ Options.DetectLeaks = Flags.detect_leaks;
+ Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval;
+ Options.TraceMalloc = Flags.trace_malloc;
+ Options.RssLimitMb = Flags.rss_limit_mb;
+ Options.MallocLimitMb = Flags.malloc_limit_mb;
+ if (!Options.MallocLimitMb)
+ Options.MallocLimitMb = Options.RssLimitMb;
+ if (Flags.runs >= 0)
+ Options.MaxNumberOfRuns = Flags.runs;
+ if (!Inputs->empty() && !Flags.minimize_crash_internal_step)
+ Options.OutputCorpus = (*Inputs)[0];
+ Options.ReportSlowUnits = Flags.report_slow_units;
+ if (Flags.artifact_prefix)
+ Options.ArtifactPrefix = Flags.artifact_prefix;
+ if (Flags.exact_artifact_path)
+ Options.ExactArtifactPath = Flags.exact_artifact_path;
+ Vector<Unit> Dictionary;
+ if (Flags.dict)
+ if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
+ return 1;
+ if (Flags.verbosity > 0 && !Dictionary.empty())
+ Printf("Dictionary: %zd entries\n", Dictionary.size());
+ bool DoPlainRun = AllInputsAreFiles();
+ Options.SaveArtifacts =
+ !DoPlainRun || Flags.minimize_crash_internal_step;
+ Options.PrintNewCovPcs = Flags.print_pcs;
+ Options.PrintNewCovFuncs = Flags.print_funcs;
+ Options.PrintFinalStats = Flags.print_final_stats;
+ Options.PrintCorpusStats = Flags.print_corpus_stats;
+ Options.PrintCoverage = Flags.print_coverage;
+ Options.DumpCoverage = Flags.dump_coverage;
+ Options.UseClangCoverage = Flags.use_clang_coverage;
+ Options.UseFeatureFrequency = Flags.use_feature_frequency;
+ if (Flags.exit_on_src_pos)
+ Options.ExitOnSrcPos = Flags.exit_on_src_pos;
+ if (Flags.exit_on_item)
+ Options.ExitOnItem = Flags.exit_on_item;
+
+ unsigned Seed = Flags.seed;
+ // Initialize Seed.
+ if (Seed == 0)
+ Seed =
+ std::chrono::system_clock::now().time_since_epoch().count() + GetPid();
+ if (Flags.verbosity)
+ Printf("INFO: Seed: %u\n", Seed);
+
+ Random Rand(Seed);
+ auto *MD = new MutationDispatcher(Rand, Options);
+ auto *Corpus = new InputCorpus(Options.OutputCorpus);
+ auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
+
+ for (auto &U: Dictionary)
+ if (U.size() <= Word::GetMaxSize())
+ MD->AddWordToManualDictionary(Word(U.data(), U.size()));
+
+ StartRssThread(F, Flags.rss_limit_mb);
+
+ Options.HandleAbrt = Flags.handle_abrt;
+ Options.HandleBus = Flags.handle_bus;
+ Options.HandleFpe = Flags.handle_fpe;
+ Options.HandleIll = Flags.handle_ill;
+ Options.HandleInt = Flags.handle_int;
+ Options.HandleSegv = Flags.handle_segv;
+ Options.HandleTerm = Flags.handle_term;
+ Options.HandleXfsz = Flags.handle_xfsz;
+ Options.HandleUsr1 = Flags.handle_usr1;
+ Options.HandleUsr2 = Flags.handle_usr2;
+ SetSignalHandler(Options);
+
+ std::atexit(Fuzzer::StaticExitCallback);
+
+ if (Flags.minimize_crash)
+ return MinimizeCrashInput(Args, Options);
+
+ if (Flags.minimize_crash_internal_step)
+ return MinimizeCrashInputInternalStep(F, Corpus);
+
+ if (Flags.cleanse_crash)
+ return CleanseCrashInput(Args, Options);
+
+ if (auto Name = Flags.run_equivalence_server) {
+ SMR.Destroy(Name);
+ if (!SMR.Create(Name)) {
+ Printf("ERROR: can't create shared memory region\n");
+ return 1;
+ }
+ Printf("INFO: EQUIVALENCE SERVER UP\n");
+ while (true) {
+ SMR.WaitClient();
+ size_t Size = SMR.ReadByteArraySize();
+ SMR.WriteByteArray(nullptr, 0);
+ const Unit tmp(SMR.GetByteArray(), SMR.GetByteArray() + Size);
+ F->ExecuteCallback(tmp.data(), tmp.size());
+ SMR.PostServer();
+ }
+ return 0;
+ }
+
+ if (auto Name = Flags.use_equivalence_server) {
+ if (!SMR.Open(Name)) {
+ Printf("ERROR: can't open shared memory region\n");
+ return 1;
+ }
+ Printf("INFO: EQUIVALENCE CLIENT UP\n");
+ }
+
+ if (DoPlainRun) {
+ Options.SaveArtifacts = false;
+ int Runs = std::max(1, Flags.runs);
+ Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(),
+ Inputs->size(), Runs);
+ for (auto &Path : *Inputs) {
+ auto StartTime = system_clock::now();
+ Printf("Running: %s\n", Path.c_str());
+ for (int Iter = 0; Iter < Runs; Iter++)
+ RunOneTest(F, Path.c_str(), Options.MaxLen);
+ auto StopTime = system_clock::now();
+ auto MS = duration_cast<milliseconds>(StopTime - StartTime).count();
+ Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS);
+ }
+ Printf("***\n"
+ "*** NOTE: fuzzing was not performed, you have only\n"
+ "*** executed the target code on a fixed set of inputs.\n"
+ "***\n");
+ F->PrintFinalStats();
+ exit(0);
+ }
+
+ if (Flags.merge) {
+ F->CrashResistantMerge(Args, *Inputs,
+ Flags.load_coverage_summary,
+ Flags.save_coverage_summary,
+ Flags.merge_control_file);
+ exit(0);
+ }
+
+ if (Flags.merge_inner) {
+ const size_t kDefaultMaxMergeLen = 1 << 20;
+ if (Options.MaxLen == 0)
+ F->SetMaxInputLen(kDefaultMaxMergeLen);
+ assert(Flags.merge_control_file);
+ F->CrashResistantMergeInternalStep(Flags.merge_control_file);
+ exit(0);
+ }
+
+ if (Flags.analyze_dict) {
+ size_t MaxLen = INT_MAX; // Large max length.
+ UnitVector InitialCorpus;
+ for (auto &Inp : *Inputs) {
+ Printf("Loading corpus dir: %s\n", Inp.c_str());
+ ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
+ MaxLen, /*ExitOnError=*/false);
+ }
+
+ if (Dictionary.empty() || Inputs->empty()) {
+ Printf("ERROR: can't analyze dict without dict and corpus provided\n");
+ return 1;
+ }
+ if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) {
+ Printf("Dictionary analysis failed\n");
+ exit(1);
+ }
+ Printf("Dictionary analysis suceeded\n");
+ exit(0);
+ }
+
+ F->Loop(*Inputs);
+
+ if (Flags.verbosity)
+ Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
+ F->secondsSinceProcessStartUp());
+ F->PrintFinalStats();
+
+ exit(0); // Don't let F destroy itself.
+}
+
+// Storage for global ExternalFunctions object.
+ExternalFunctions *EF = nullptr;
+
+} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerExtFunctions.def b/lib/fuzzer/FuzzerExtFunctions.def
new file mode 100644
index 000000000000..25a655bfd71d
--- /dev/null
+++ b/lib/fuzzer/FuzzerExtFunctions.def
@@ -0,0 +1,47 @@
+//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This defines the external function pointers that
+// ``fuzzer::ExternalFunctions`` should contain and try to initialize. The
+// EXT_FUNC macro must be defined at the point of inclusion. The signature of
+// the macro is:
+//
+// EXT_FUNC(<name>, <return_type>, <function_signature>, <warn_if_missing>)
+//===----------------------------------------------------------------------===//
+
+// Optional user functions
+EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false);
+EXT_FUNC(LLVMFuzzerCustomMutator, size_t,
+ (uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed),
+ false);
+EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
+ (const uint8_t * Data1, size_t Size1,
+ const uint8_t * Data2, size_t Size2,
+ uint8_t * Out, size_t MaxOutSize, unsigned int Seed),
+ false);
+
+// Sanitizer functions
+EXT_FUNC(__lsan_enable, void, (), false);
+EXT_FUNC(__lsan_disable, void, (), false);
+EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false);
+EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
+ (void (*malloc_hook)(const volatile void *, size_t),
+ void (*free_hook)(const volatile void *)),
+ false);
+EXT_FUNC(__sanitizer_purge_allocator, void, (), false);
+EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t, size_t), false);
+EXT_FUNC(__sanitizer_print_stack_trace, void, (), true);
+EXT_FUNC(__sanitizer_symbolize_pc, void,
+ (void *, const char *fmt, char *out_buf, size_t out_buf_size), false);
+EXT_FUNC(__sanitizer_get_module_and_offset_for_pc, int,
+ (void *pc, char *module_path,
+ size_t module_path_len,void **pc_offset), false);
+EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
+EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);
+EXT_FUNC(__sanitizer_dump_coverage, void, (const uintptr_t *, uintptr_t),
+ false);
diff --git a/lib/fuzzer/FuzzerExtFunctions.h b/lib/fuzzer/FuzzerExtFunctions.h
new file mode 100644
index 000000000000..2672a385478d
--- /dev/null
+++ b/lib/fuzzer/FuzzerExtFunctions.h
@@ -0,0 +1,35 @@
+//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Defines an interface to (possibly optional) functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_EXT_FUNCTIONS_H
+#define LLVM_FUZZER_EXT_FUNCTIONS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace fuzzer {
+
+struct ExternalFunctions {
+ // Initialize function pointers. Functions that are not available will be set
+ // to nullptr. Do not call this constructor before ``main()`` has been
+ // entered.
+ ExternalFunctions();
+
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ RETURN_TYPE(*NAME) FUNC_SIG = nullptr
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+};
+} // namespace fuzzer
+
+#endif
diff --git a/lib/fuzzer/FuzzerExtFunctionsDlsym.cpp b/lib/fuzzer/FuzzerExtFunctionsDlsym.cpp
new file mode 100644
index 000000000000..06bddd5de38f
--- /dev/null
+++ b/lib/fuzzer/FuzzerExtFunctionsDlsym.cpp
@@ -0,0 +1,52 @@
+//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation for operating systems that support dlsym(). We only use it on
+// Apple platforms for now. We don't use this approach on Linux because it
+// requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker.
+// That is a complication we don't wish to expose to clients right now.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_APPLE
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include <dlfcn.h>
+
+using namespace fuzzer;
+
+template <typename T>
+static T GetFnPtr(const char *FnName, bool WarnIfMissing) {
+ dlerror(); // Clear any previous errors.
+ void *Fn = dlsym(RTLD_DEFAULT, FnName);
+ if (Fn == nullptr) {
+ if (WarnIfMissing) {
+ const char *ErrorMsg = dlerror();
+ Printf("WARNING: Failed to find function \"%s\".", FnName);
+ if (ErrorMsg)
+ Printf(" Reason %s.", ErrorMsg);
+ Printf("\n");
+ }
+ }
+ return reinterpret_cast<T>(Fn);
+}
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ this->NAME = GetFnPtr<decltype(ExternalFunctions::NAME)>(#NAME, WARN)
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_APPLE
diff --git a/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp b/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp
new file mode 100644
index 000000000000..321b3ec5d414
--- /dev/null
+++ b/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp
@@ -0,0 +1,62 @@
+//===- FuzzerExtFunctionsDlsymWin.cpp - Interface to external functions ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation using dynamic loading for Windows.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_WINDOWS
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include "Windows.h"
+
+// This must be included after Windows.h.
+#include "Psapi.h"
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+ HMODULE Modules[1024];
+ DWORD BytesNeeded;
+ HANDLE CurrentProcess = GetCurrentProcess();
+
+ if (!EnumProcessModules(CurrentProcess, Modules, sizeof(Modules),
+ &BytesNeeded)) {
+ Printf("EnumProcessModules failed (error: %d).\n", GetLastError());
+ exit(1);
+ }
+
+ if (sizeof(Modules) < BytesNeeded) {
+ Printf("Error: the array is not big enough to hold all loaded modules.\n");
+ exit(1);
+ }
+
+ for (size_t i = 0; i < (BytesNeeded / sizeof(HMODULE)); i++)
+ {
+ FARPROC Fn;
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ if (this->NAME == nullptr) { \
+ Fn = GetProcAddress(Modules[i], #NAME); \
+ if (Fn == nullptr) \
+ Fn = GetProcAddress(Modules[i], #NAME "__dll"); \
+ this->NAME = (decltype(ExternalFunctions::NAME)) Fn; \
+ }
+#include "FuzzerExtFunctions.def"
+#undef EXT_FUNC
+ }
+
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ if (this->NAME == nullptr && WARN) \
+ Printf("WARNING: Failed to find function \"%s\".\n", #NAME);
+#include "FuzzerExtFunctions.def"
+#undef EXT_FUNC
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_WINDOWS
diff --git a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp
new file mode 100644
index 000000000000..5a90723986af
--- /dev/null
+++ b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp
@@ -0,0 +1,54 @@
+//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation for Linux. This relies on the linker's support for weak
+// symbols. We don't use this approach on Apple platforms because it requires
+// clients of LibFuzzer to pass ``-U _<symbol_name>`` to the linker to allow
+// weak symbols to be undefined. That is a complication we don't want to expose
+// to clients right now.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FUCHSIA
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+
+extern "C" {
+// Declare these symbols as weak to allow them to be optionally defined.
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+using namespace fuzzer;
+
+static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) {
+ if (FnPtr == nullptr && WarnIfMissing) {
+ Printf("WARNING: Failed to find function \"%s\".\n", FnName);
+ }
+}
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ this->NAME = ::NAME; \
+ CheckFnPtr(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(::NAME)), \
+ #NAME, WARN);
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_LINUX || LIBFUZZER_NETBSD
diff --git a/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp b/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp
new file mode 100644
index 000000000000..e10f7b4dcac2
--- /dev/null
+++ b/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp
@@ -0,0 +1,56 @@
+//===- FuzzerExtFunctionsWeakAlias.cpp - Interface to external functions --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation using weak aliases. Works for Windows.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_WINDOWS
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+
+using namespace fuzzer;
+
+extern "C" {
+// Declare these symbols as weak to allow them to be optionally defined.
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ RETURN_TYPE NAME##Def FUNC_SIG { \
+ Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \
+ exit(1); \
+ } \
+ RETURN_TYPE NAME FUNC_SIG __attribute__((weak, alias(#NAME "Def")));
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+template <typename T>
+static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) {
+ if (Fun == FunDef) {
+ if (WarnIfMissing)
+ Printf("WARNING: Failed to find function \"%s\".\n", FnName);
+ return nullptr;
+ }
+ return Fun;
+}
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN);
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_WINDOWS
diff --git a/lib/fuzzer/FuzzerExtraCounters.cpp b/lib/fuzzer/FuzzerExtraCounters.cpp
new file mode 100644
index 000000000000..0e7a7761bf80
--- /dev/null
+++ b/lib/fuzzer/FuzzerExtraCounters.cpp
@@ -0,0 +1,41 @@
+//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Extra coverage counters defined by user code.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD
+__attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters;
+__attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters;
+
+namespace fuzzer {
+uint8_t *ExtraCountersBegin() { return &__start___libfuzzer_extra_counters; }
+uint8_t *ExtraCountersEnd() { return &__stop___libfuzzer_extra_counters; }
+ATTRIBUTE_NO_SANITIZE_ALL
+void ClearExtraCounters() { // hand-written memset, don't asan-ify.
+ uintptr_t *Beg = reinterpret_cast<uintptr_t*>(ExtraCountersBegin());
+ uintptr_t *End = reinterpret_cast<uintptr_t*>(ExtraCountersEnd());
+ for (; Beg < End; Beg++) {
+ *Beg = 0;
+ __asm__ __volatile__("" : : : "memory");
+ }
+}
+
+} // namespace fuzzer
+
+#else
+// TODO: implement for other platforms.
+namespace fuzzer {
+uint8_t *ExtraCountersBegin() { return nullptr; }
+uint8_t *ExtraCountersEnd() { return nullptr; }
+void ClearExtraCounters() {}
+} // namespace fuzzer
+
+#endif
diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def
new file mode 100644
index 000000000000..a32102a7da07
--- /dev/null
+++ b/lib/fuzzer/FuzzerFlags.def
@@ -0,0 +1,150 @@
+//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the
+// point of inclusion. We are not using any flag parsing library for better
+// portability and independence.
+//===----------------------------------------------------------------------===//
+FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.")
+FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.")
+FUZZER_FLAG_INT(runs, -1,
+ "Number of individual test runs (-1 for infinite runs).")
+FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "
+ "If 0, libFuzzer tries to guess a good value based on the corpus "
+ "and reports it. ")
+FUZZER_FLAG_INT(experimental_len_control, 0, "experimental flag")
+FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.")
+FUZZER_FLAG_INT(mutate_depth, 5,
+ "Apply this number of consecutive mutations to each input.")
+FUZZER_FLAG_INT(reduce_depth, 0, "Experimental/internal. "
+ "Reduce depth if mutations lose unique features")
+FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup")
+FUZZER_FLAG_INT(prefer_small, 1,
+ "If 1, always prefer smaller inputs during the corpus shuffle.")
+FUZZER_FLAG_INT(
+ timeout, 1200,
+ "Timeout in seconds (if positive). "
+ "If one unit runs more than this number of seconds the process will abort.")
+FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug "
+ "this exit code will be used.")
+FUZZER_FLAG_INT(timeout_exitcode, 77, "When libFuzzer reports a timeout "
+ "this exit code will be used.")
+FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
+ "time in seconds to run the fuzzer.")
+FUZZER_FLAG_INT(help, 0, "Print help.")
+FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
+ "merged into the 1-st corpus. Only interesting units will be taken. "
+ "This flag can be used to minimize a corpus.")
+FUZZER_FLAG_STRING(merge_inner, "internal flag")
+FUZZER_FLAG_STRING(merge_control_file,
+ "Specify a control file used for the merge proccess. "
+ "If a merge process gets killed it tries to leave this file "
+ "in a state suitable for resuming the merge. "
+ "By default a temporary file will be used.")
+FUZZER_FLAG_STRING(save_coverage_summary, "Experimental:"
+ " save coverage summary to a given file."
+ " Used with -merge=1")
+FUZZER_FLAG_STRING(load_coverage_summary, "Experimental:"
+ " load coverage summary from a given file."
+ " Treat this coverage as belonging to the first corpus. "
+ " Used with -merge=1")
+FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided"
+ " crash input. Use with -runs=N or -max_total_time=N to limit "
+ "the number attempts."
+ " Use with -exact_artifact_path to specify the output."
+ " Combine with ASAN_OPTIONS=dedup_token_length=3 (or similar) to ensure that"
+ " the minimized input triggers the same crash."
+ )
+FUZZER_FLAG_INT(cleanse_crash, 0, "If 1, tries to cleanse the provided"
+ " crash input to make it contain fewer original bytes."
+ " Use with -exact_artifact_path to specify the output."
+ )
+FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag")
+FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters")
+FUZZER_FLAG_INT(use_memmem, 1,
+ "Use hints from intercepting memmem, strstr, etc")
+FUZZER_FLAG_INT(use_value_profile, 0,
+ "Experimental. Use value profile to guide fuzzing.")
+FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations")
+FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus inputs.")
+FUZZER_FLAG_INT(reduce_inputs, 1,
+ "Try to reduce the size of inputs while preserving their full feature sets")
+FUZZER_FLAG_UNSIGNED(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
+ " this number of jobs in separate worker processes"
+ " with stdout/stderr redirected to fuzz-JOB.log.")
+FUZZER_FLAG_UNSIGNED(workers, 0,
+ "Number of simultaneous worker processes to run the jobs."
+ " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.")
+FUZZER_FLAG_INT(reload, 1,
+ "Reload the main corpus every <N> seconds to get new units"
+ " discovered by other processes. If 0, disabled")
+FUZZER_FLAG_INT(report_slow_units, 10,
+ "Report slowest units if they run for more than this number of seconds.")
+FUZZER_FLAG_INT(only_ascii, 0,
+ "If 1, generate only ASCII (isprint+isspace) inputs.")
+FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.")
+FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, "
+ "timeout, or slow inputs) as "
+ "$(artifact_prefix)file")
+FUZZER_FLAG_STRING(exact_artifact_path,
+ "Write the single artifact on failure (crash, timeout) "
+ "as $(exact_artifact_path). This overrides -artifact_prefix "
+ "and will not use checksum in the file name. Do not "
+ "use the same path for several parallel processes.")
+FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
+FUZZER_FLAG_INT(print_funcs, 2, "If >=1, print out at most this number of "
+ "newly covered functions.")
+FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
+FUZZER_FLAG_INT(print_corpus_stats, 0,
+ "If 1, print statistics on corpus elements at exit.")
+FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
+ " at exit.")
+FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated."
+ " If 1, dump coverage information as a"
+ " .sancov file at exit.")
+FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
+FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.")
+FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
+FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.")
+FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.")
+FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.")
+FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
+FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.")
+FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.")
+FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.")
+FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
+ "if 2, close stderr; if 3, close both. "
+ "Be careful, this will also close e.g. stderr of asan.")
+FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
+ "try to detect memory leaks during fuzzing (i.e. not only at shut down).")
+FUZZER_FLAG_INT(purge_allocator_interval, 1, "Purge allocator caches and "
+ "quarantines every <N> seconds. When rss_limit_mb is specified (>0), "
+ "purging starts when RSS exceeds 50% of rss_limit_mb. Pass "
+ "purge_allocator_interval=-1 to disable this functionality.")
+FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. "
+ "If >= 2 will also print stack traces.")
+FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
+ "reaching this limit of RSS memory usage.")
+FUZZER_FLAG_INT(malloc_limit_mb, 0, "If non-zero, the fuzzer will exit "
+ "if the target tries to allocate this number of Mb with one malloc call. "
+ "If zero (default) same limit as rss_limit_mb is applied.")
+FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"
+ " from the given source location. Example: -exit_on_src_pos=foo.cc:123. "
+ "Used primarily for testing libFuzzer itself.")
+FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum"
+ " was added to the corpus. "
+ "Used primarily for testing libFuzzer itself.")
+FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed "
+ "after this one. Useful for fuzzers that need to do their own "
+ "argument parsing.")
+
+FUZZER_FLAG_STRING(run_equivalence_server, "Experimental")
+FUZZER_FLAG_STRING(use_equivalence_server, "Experimental")
+FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")
+FUZZER_FLAG_INT(use_clang_coverage, 0, "Experimental")
+FUZZER_FLAG_INT(use_feature_frequency, 0, "Experimental/internal")
diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp
new file mode 100644
index 000000000000..dac5ec658f1c
--- /dev/null
+++ b/lib/fuzzer/FuzzerIO.cpp
@@ -0,0 +1,129 @@
+//===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// IO functions.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerIO.h"
+#include "FuzzerDefs.h"
+#include "FuzzerExtFunctions.h"
+#include <algorithm>
+#include <cstdarg>
+#include <fstream>
+#include <iterator>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace fuzzer {
+
+static FILE *OutputFile = stderr;
+
+long GetEpoch(const std::string &Path) {
+ struct stat St;
+ if (stat(Path.c_str(), &St))
+ return 0; // Can't stat, be conservative.
+ return St.st_mtime;
+}
+
+Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
+ std::ifstream T(Path);
+ if (ExitOnError && !T) {
+ Printf("No such directory: %s; exiting\n", Path.c_str());
+ exit(1);
+ }
+
+ T.seekg(0, T.end);
+ auto EndPos = T.tellg();
+ if (EndPos < 0) return {};
+ size_t FileLen = EndPos;
+ if (MaxSize)
+ FileLen = std::min(FileLen, MaxSize);
+
+ T.seekg(0, T.beg);
+ Unit Res(FileLen);
+ T.read(reinterpret_cast<char *>(Res.data()), FileLen);
+ return Res;
+}
+
+std::string FileToString(const std::string &Path) {
+ std::ifstream T(Path);
+ return std::string((std::istreambuf_iterator<char>(T)),
+ std::istreambuf_iterator<char>());
+}
+
+void CopyFileToErr(const std::string &Path) {
+ Printf("%s", FileToString(Path).c_str());
+}
+
+void WriteToFile(const Unit &U, const std::string &Path) {
+ // Use raw C interface because this function may be called from a sig handler.
+ FILE *Out = fopen(Path.c_str(), "w");
+ if (!Out) return;
+ fwrite(U.data(), sizeof(U[0]), U.size(), Out);
+ fclose(Out);
+}
+
+void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
+ long *Epoch, size_t MaxSize, bool ExitOnError) {
+ long E = Epoch ? *Epoch : 0;
+ Vector<std::string> Files;
+ ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
+ size_t NumLoaded = 0;
+ for (size_t i = 0; i < Files.size(); i++) {
+ auto &X = Files[i];
+ if (Epoch && GetEpoch(X) < E) continue;
+ NumLoaded++;
+ if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
+ Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
+ auto S = FileToVector(X, MaxSize, ExitOnError);
+ if (!S.empty())
+ V->push_back(S);
+ }
+}
+
+
+void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V) {
+ Vector<std::string> Files;
+ ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
+ for (auto &File : Files)
+ if (size_t Size = FileSize(File))
+ V->push_back({File, Size});
+}
+
+std::string DirPlusFile(const std::string &DirPath,
+ const std::string &FileName) {
+ return DirPath + GetSeparator() + FileName;
+}
+
+void DupAndCloseStderr() {
+ int OutputFd = DuplicateFile(2);
+ if (OutputFd > 0) {
+ FILE *NewOutputFile = OpenFile(OutputFd, "w");
+ if (NewOutputFile) {
+ OutputFile = NewOutputFile;
+ if (EF->__sanitizer_set_report_fd)
+ EF->__sanitizer_set_report_fd(
+ reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));
+ DiscardOutput(2);
+ }
+ }
+}
+
+void CloseStdout() {
+ DiscardOutput(1);
+}
+
+void Printf(const char *Fmt, ...) {
+ va_list ap;
+ va_start(ap, Fmt);
+ vfprintf(OutputFile, Fmt, ap);
+ va_end(ap);
+ fflush(OutputFile);
+}
+
+} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h
new file mode 100644
index 000000000000..ea9f0d5a6703
--- /dev/null
+++ b/lib/fuzzer/FuzzerIO.h
@@ -0,0 +1,85 @@
+//===- FuzzerIO.h - Internal header for IO utils ----------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// IO interface.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_IO_H
+#define LLVM_FUZZER_IO_H
+
+#include "FuzzerDefs.h"
+
+namespace fuzzer {
+
+long GetEpoch(const std::string &Path);
+
+Unit FileToVector(const std::string &Path, size_t MaxSize = 0,
+ bool ExitOnError = true);
+
+std::string FileToString(const std::string &Path);
+
+void CopyFileToErr(const std::string &Path);
+
+void WriteToFile(const Unit &U, const std::string &Path);
+
+void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
+ long *Epoch, size_t MaxSize, bool ExitOnError);
+
+// Returns "Dir/FileName" or equivalent for the current OS.
+std::string DirPlusFile(const std::string &DirPath,
+ const std::string &FileName);
+
+// Returns the name of the dir, similar to the 'dirname' utility.
+std::string DirName(const std::string &FileName);
+
+// Returns path to a TmpDir.
+std::string TmpDir();
+
+bool IsInterestingCoverageFile(const std::string &FileName);
+
+void DupAndCloseStderr();
+
+void CloseStdout();
+
+void Printf(const char *Fmt, ...);
+
+// Print using raw syscalls, useful when printing at early init stages.
+void RawPrint(const char *Str);
+
+// Platform specific functions:
+bool IsFile(const std::string &Path);
+size_t FileSize(const std::string &Path);
+
+void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+ Vector<std::string> *V, bool TopDir);
+
+struct SizedFile {
+ std::string File;
+ size_t Size;
+ bool operator<(const SizedFile &B) const { return Size < B.Size; }
+};
+
+void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
+
+char GetSeparator();
+
+FILE* OpenFile(int Fd, const char *Mode);
+
+int CloseFile(int Fd);
+
+int DuplicateFile(int Fd);
+
+void RemoveFile(const std::string &Path);
+
+void DiscardOutput(int Fd);
+
+intptr_t GetHandleFromFd(int fd);
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_IO_H
diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp
new file mode 100644
index 000000000000..2257751c662d
--- /dev/null
+++ b/lib/fuzzer/FuzzerIOPosix.cpp
@@ -0,0 +1,140 @@
+//===- FuzzerIOPosix.cpp - IO utils for Posix. ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// IO functions implementation using Posix API.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_POSIX || LIBFUZZER_FUCHSIA
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include <cstdarg>
+#include <cstdio>
+#include <dirent.h>
+#include <fstream>
+#include <iterator>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace fuzzer {
+
+bool IsFile(const std::string &Path) {
+ struct stat St;
+ if (stat(Path.c_str(), &St))
+ return false;
+ return S_ISREG(St.st_mode);
+}
+
+static bool IsDirectory(const std::string &Path) {
+ struct stat St;
+ if (stat(Path.c_str(), &St))
+ return false;
+ return S_ISDIR(St.st_mode);
+}
+
+size_t FileSize(const std::string &Path) {
+ struct stat St;
+ if (stat(Path.c_str(), &St))
+ return 0;
+ return St.st_size;
+}
+
+void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+ Vector<std::string> *V, bool TopDir) {
+ auto E = GetEpoch(Dir);
+ if (Epoch)
+ if (E && *Epoch >= E) return;
+
+ DIR *D = opendir(Dir.c_str());
+ if (!D) {
+ Printf("No such directory: %s; exiting\n", Dir.c_str());
+ exit(1);
+ }
+ while (auto E = readdir(D)) {
+ std::string Path = DirPlusFile(Dir, E->d_name);
+ if (E->d_type == DT_REG || E->d_type == DT_LNK ||
+ (E->d_type == DT_UNKNOWN && IsFile(Path)))
+ V->push_back(Path);
+ else if ((E->d_type == DT_DIR ||
+ (E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
+ *E->d_name != '.')
+ ListFilesInDirRecursive(Path, Epoch, V, false);
+ }
+ closedir(D);
+ if (Epoch && TopDir)
+ *Epoch = E;
+}
+
+char GetSeparator() {
+ return '/';
+}
+
+FILE* OpenFile(int Fd, const char* Mode) {
+ return fdopen(Fd, Mode);
+}
+
+int CloseFile(int fd) {
+ return close(fd);
+}
+
+int DuplicateFile(int Fd) {
+ return dup(Fd);
+}
+
+void RemoveFile(const std::string &Path) {
+ unlink(Path.c_str());
+}
+
+void DiscardOutput(int Fd) {
+ FILE* Temp = fopen("/dev/null", "w");
+ if (!Temp)
+ return;
+ dup2(fileno(Temp), Fd);
+ fclose(Temp);
+}
+
+intptr_t GetHandleFromFd(int fd) {
+ return static_cast<intptr_t>(fd);
+}
+
+std::string DirName(const std::string &FileName) {
+ char *Tmp = new char[FileName.size() + 1];
+ memcpy(Tmp, FileName.c_str(), FileName.size() + 1);
+ std::string Res = dirname(Tmp);
+ delete [] Tmp;
+ return Res;
+}
+
+std::string TmpDir() {
+ if (auto Env = getenv("TMPDIR"))
+ return Env;
+ return "/tmp";
+}
+
+bool IsInterestingCoverageFile(const std::string &FileName) {
+ if (FileName.find("compiler-rt/lib/") != std::string::npos)
+ return false; // sanitizer internal.
+ if (FileName.find("/usr/lib/") != std::string::npos)
+ return false;
+ if (FileName.find("/usr/include/") != std::string::npos)
+ return false;
+ if (FileName == "<null>")
+ return false;
+ return true;
+}
+
+
+void RawPrint(const char *Str) {
+ write(2, Str, strlen(Str));
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_POSIX
diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp
new file mode 100644
index 000000000000..74853646b213
--- /dev/null
+++ b/lib/fuzzer/FuzzerIOWindows.cpp
@@ -0,0 +1,323 @@
+//===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// IO functions implementation for Windows.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_WINDOWS
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include <cstdarg>
+#include <cstdio>
+#include <fstream>
+#include <io.h>
+#include <iterator>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <windows.h>
+
+namespace fuzzer {
+
+static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {
+
+ if (FileAttributes & FILE_ATTRIBUTE_NORMAL)
+ return true;
+
+ if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ return false;
+
+ HANDLE FileHandle(
+ CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0));
+
+ if (FileHandle == INVALID_HANDLE_VALUE) {
+ Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
+ GetLastError());
+ return false;
+ }
+
+ DWORD FileType = GetFileType(FileHandle);
+
+ if (FileType == FILE_TYPE_UNKNOWN) {
+ Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
+ GetLastError());
+ CloseHandle(FileHandle);
+ return false;
+ }
+
+ if (FileType != FILE_TYPE_DISK) {
+ CloseHandle(FileHandle);
+ return false;
+ }
+
+ CloseHandle(FileHandle);
+ return true;
+}
+
+bool IsFile(const std::string &Path) {
+ DWORD Att = GetFileAttributesA(Path.c_str());
+
+ if (Att == INVALID_FILE_ATTRIBUTES) {
+ Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
+ Path.c_str(), GetLastError());
+ return false;
+ }
+
+ return IsFile(Path, Att);
+}
+
+void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+ Vector<std::string> *V, bool TopDir) {
+ auto E = GetEpoch(Dir);
+ if (Epoch)
+ if (E && *Epoch >= E) return;
+
+ std::string Path(Dir);
+ assert(!Path.empty());
+ if (Path.back() != '\\')
+ Path.push_back('\\');
+ Path.push_back('*');
+
+ // Get the first directory entry.
+ WIN32_FIND_DATAA FindInfo;
+ HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
+ if (FindHandle == INVALID_HANDLE_VALUE)
+ {
+ if (GetLastError() == ERROR_FILE_NOT_FOUND)
+ return;
+ Printf("No such directory: %s; exiting\n", Dir.c_str());
+ exit(1);
+ }
+
+ do {
+ std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);
+
+ if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ size_t FilenameLen = strlen(FindInfo.cFileName);
+ if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
+ (FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
+ FindInfo.cFileName[1] == '.'))
+ continue;
+
+ ListFilesInDirRecursive(FileName, Epoch, V, false);
+ }
+ else if (IsFile(FileName, FindInfo.dwFileAttributes))
+ V->push_back(FileName);
+ } while (FindNextFileA(FindHandle, &FindInfo));
+
+ DWORD LastError = GetLastError();
+ if (LastError != ERROR_NO_MORE_FILES)
+ Printf("FindNextFileA failed (Error code: %lu).\n", LastError);
+
+ FindClose(FindHandle);
+
+ if (Epoch && TopDir)
+ *Epoch = E;
+}
+
+char GetSeparator() {
+ return '\\';
+}
+
+FILE* OpenFile(int Fd, const char* Mode) {
+ return _fdopen(Fd, Mode);
+}
+
+int CloseFile(int Fd) {
+ return _close(Fd);
+}
+
+int DuplicateFile(int Fd) {
+ return _dup(Fd);
+}
+
+void RemoveFile(const std::string &Path) {
+ _unlink(Path.c_str());
+}
+
+void DiscardOutput(int Fd) {
+ FILE* Temp = fopen("nul", "w");
+ if (!Temp)
+ return;
+ _dup2(_fileno(Temp), Fd);
+ fclose(Temp);
+}
+
+intptr_t GetHandleFromFd(int fd) {
+ return _get_osfhandle(fd);
+}
+
+static bool IsSeparator(char C) {
+ return C == '\\' || C == '/';
+}
+
+// Parse disk designators, like "C:\". If Relative == true, also accepts: "C:".
+// Returns number of characters considered if successful.
+static size_t ParseDrive(const std::string &FileName, const size_t Offset,
+ bool Relative = true) {
+ if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':')
+ return 0;
+ if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) {
+ if (!Relative) // Accept relative path?
+ return 0;
+ else
+ return 2;
+ }
+ return 3;
+}
+
+// Parse a file name, like: SomeFile.txt
+// Returns number of characters considered if successful.
+static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
+ size_t Pos = Offset;
+ const size_t End = FileName.size();
+ for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
+ ;
+ return Pos - Offset;
+}
+
+// Parse a directory ending in separator, like: `SomeDir\`
+// Returns number of characters considered if successful.
+static size_t ParseDir(const std::string &FileName, const size_t Offset) {
+ size_t Pos = Offset;
+ const size_t End = FileName.size();
+ if (Pos >= End || IsSeparator(FileName[Pos]))
+ return 0;
+ for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
+ ;
+ if (Pos >= End)
+ return 0;
+ ++Pos; // Include separator.
+ return Pos - Offset;
+}
+
+// Parse a servername and share, like: `SomeServer\SomeShare\`
+// Returns number of characters considered if successful.
+static size_t ParseServerAndShare(const std::string &FileName,
+ const size_t Offset) {
+ size_t Pos = Offset, Res;
+ if (!(Res = ParseDir(FileName, Pos)))
+ return 0;
+ Pos += Res;
+ if (!(Res = ParseDir(FileName, Pos)))
+ return 0;
+ Pos += Res;
+ return Pos - Offset;
+}
+
+// Parse the given Ref string from the position Offset, to exactly match the given
+// string Patt.
+// Returns number of characters considered if successful.
+static size_t ParseCustomString(const std::string &Ref, size_t Offset,
+ const char *Patt) {
+ size_t Len = strlen(Patt);
+ if (Offset + Len > Ref.size())
+ return 0;
+ return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0;
+}
+
+// Parse a location, like:
+// \\?\UNC\Server\Share\ \\?\C:\ \\Server\Share\ \ C:\ C:
+// Returns number of characters considered if successful.
+static size_t ParseLocation(const std::string &FileName) {
+ size_t Pos = 0, Res;
+
+ if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) {
+ Pos += Res;
+ if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) {
+ Pos += Res;
+ if ((Res = ParseServerAndShare(FileName, Pos)))
+ return Pos + Res;
+ return 0;
+ }
+ if ((Res = ParseDrive(FileName, Pos, false)))
+ return Pos + Res;
+ return 0;
+ }
+
+ if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
+ ++Pos;
+ if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
+ ++Pos;
+ if ((Res = ParseServerAndShare(FileName, Pos)))
+ return Pos + Res;
+ return 0;
+ }
+ return Pos;
+ }
+
+ if ((Res = ParseDrive(FileName, Pos)))
+ return Pos + Res;
+
+ return Pos;
+}
+
+std::string DirName(const std::string &FileName) {
+ size_t LocationLen = ParseLocation(FileName);
+ size_t DirLen = 0, Res;
+ while ((Res = ParseDir(FileName, LocationLen + DirLen)))
+ DirLen += Res;
+ size_t FileLen = ParseFileName(FileName, LocationLen + DirLen);
+
+ if (LocationLen + DirLen + FileLen != FileName.size()) {
+ Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str());
+ exit(1);
+ }
+
+ if (DirLen) {
+ --DirLen; // Remove trailing separator.
+ if (!FileLen) { // Path ended in separator.
+ assert(DirLen);
+ // Remove file name from Dir.
+ while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1]))
+ --DirLen;
+ if (DirLen) // Remove trailing separator.
+ --DirLen;
+ }
+ }
+
+ if (!LocationLen) { // Relative path.
+ if (!DirLen)
+ return ".";
+ return std::string(".\\").append(FileName, 0, DirLen);
+ }
+
+ return FileName.substr(0, LocationLen + DirLen);
+}
+
+std::string TmpDir() {
+ std::string Tmp;
+ Tmp.resize(MAX_PATH + 1);
+ DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]);
+ if (Size == 0) {
+ Printf("Couldn't get Tmp path.\n");
+ exit(1);
+ }
+ Tmp.resize(Size);
+ return Tmp;
+}
+
+bool IsInterestingCoverageFile(const std::string &FileName) {
+ if (FileName.find("Program Files") != std::string::npos)
+ return false;
+ if (FileName.find("compiler-rt\\lib\\") != std::string::npos)
+ return false; // sanitizer internal.
+ if (FileName == "<null>")
+ return false;
+ return true;
+}
+
+void RawPrint(const char *Str) {
+ // Not tested, may or may not work. Fix if needed.
+ Printf("%s", Str);
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_WINDOWS
diff --git a/lib/fuzzer/FuzzerInterface.h b/lib/fuzzer/FuzzerInterface.h
new file mode 100644
index 000000000000..c2c0a39843c0
--- /dev/null
+++ b/lib/fuzzer/FuzzerInterface.h
@@ -0,0 +1,67 @@
+//===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Define the interface between libFuzzer and the library being tested.
+//===----------------------------------------------------------------------===//
+
+// NOTE: the libFuzzer interface is thin and in the majority of cases
+// you should not include this file into your target. In 95% of cases
+// all you need is to define the following function in your file:
+// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+// WARNING: keep the interface in C.
+
+#ifndef LLVM_FUZZER_INTERFACE_H
+#define LLVM_FUZZER_INTERFACE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Mandatory user-provided target function.
+// Executes the code under test with [Data, Data+Size) as the input.
+// libFuzzer will invoke this function *many* times with different inputs.
+// Must return 0.
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+// Optional user-provided initialization function.
+// If provided, this function will be called by libFuzzer once at startup.
+// It may read and modify argc/argv.
+// Must return 0.
+int LLVMFuzzerInitialize(int *argc, char ***argv);
+
+// Optional user-provided custom mutator.
+// Mutates raw data in [Data, Data+Size) inplace.
+// Returns the new size, which is not greater than MaxSize.
+// Given the same Seed produces the same mutation.
+size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize,
+ unsigned int Seed);
+
+// Optional user-provided custom cross-over function.
+// Combines pieces of Data1 & Data2 together into Out.
+// Returns the new size, which is not greater than MaxOutSize.
+// Should produce the same mutation given the same Seed.
+size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
+ const uint8_t *Data2, size_t Size2,
+ uint8_t *Out, size_t MaxOutSize,
+ unsigned int Seed);
+
+// Experimental, may go away in future.
+// libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator.
+// Mutates raw data in [Data, Data+Size) inplace.
+// Returns the new size, which is not greater than MaxSize.
+size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif // LLVM_FUZZER_INTERFACE_H
diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h
new file mode 100644
index 000000000000..2b2638f1f8f2
--- /dev/null
+++ b/lib/fuzzer/FuzzerInternal.h
@@ -0,0 +1,155 @@
+//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Define the main class fuzzer::Fuzzer and most functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_INTERNAL_H
+#define LLVM_FUZZER_INTERNAL_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerExtFunctions.h"
+#include "FuzzerInterface.h"
+#include "FuzzerOptions.h"
+#include "FuzzerSHA1.h"
+#include "FuzzerValueBitMap.h"
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <climits>
+#include <cstdlib>
+#include <string.h>
+
+namespace fuzzer {
+
+using namespace std::chrono;
+
+class Fuzzer {
+public:
+
+ Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
+ FuzzingOptions Options);
+ ~Fuzzer();
+ void Loop(const Vector<std::string> &CorpusDirs);
+ void ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs);
+ void MinimizeCrashLoop(const Unit &U);
+ void RereadOutputCorpus(size_t MaxSize);
+
+ size_t secondsSinceProcessStartUp() {
+ return duration_cast<seconds>(system_clock::now() - ProcessStartTime)
+ .count();
+ }
+
+ bool TimedOut() {
+ return Options.MaxTotalTimeSec > 0 &&
+ secondsSinceProcessStartUp() >
+ static_cast<size_t>(Options.MaxTotalTimeSec);
+ }
+
+ size_t execPerSec() {
+ size_t Seconds = secondsSinceProcessStartUp();
+ return Seconds ? TotalNumberOfRuns / Seconds : 0;
+ }
+
+ size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
+
+ static void StaticAlarmCallback();
+ static void StaticCrashSignalCallback();
+ static void StaticExitCallback();
+ static void StaticInterruptCallback();
+ static void StaticFileSizeExceedCallback();
+ static void StaticGracefulExitCallback();
+
+ void ExecuteCallback(const uint8_t *Data, size_t Size);
+ bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
+ InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr);
+
+ // Merge Corpora[1:] into Corpora[0].
+ void Merge(const Vector<std::string> &Corpora);
+ void CrashResistantMerge(const Vector<std::string> &Args,
+ const Vector<std::string> &Corpora,
+ const char *CoverageSummaryInputPathOrNull,
+ const char *CoverageSummaryOutputPathOrNull,
+ const char *MergeControlFilePathOrNull);
+ void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
+ MutationDispatcher &GetMD() { return MD; }
+ void PrintFinalStats();
+ void SetMaxInputLen(size_t MaxInputLen);
+ void SetMaxMutationLen(size_t MaxMutationLen);
+ void RssLimitCallback();
+
+ bool InFuzzingThread() const { return IsMyThread; }
+ size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const;
+ void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
+ bool DuringInitialCorpusExecution);
+
+ void HandleMalloc(size_t Size);
+ void AnnounceOutput(const uint8_t *Data, size_t Size);
+
+private:
+ void AlarmCallback();
+ void CrashCallback();
+ void ExitCallback();
+ void MaybeExitGracefully();
+ void CrashOnOverwrittenData();
+ void InterruptCallback();
+ void MutateAndTestOne();
+ void PurgeAllocator();
+ void ReportNewCoverage(InputInfo *II, const Unit &U);
+ void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size);
+ void WriteToOutputCorpus(const Unit &U);
+ void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
+ void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0);
+ void PrintStatusForNewUnit(const Unit &U, const char *Text);
+ void CheckExitOnSrcPosOrItem();
+
+ static void StaticDeathCallback();
+ void DumpCurrentUnit(const char *Prefix);
+ void DeathCallback();
+
+ void AllocateCurrentUnitData();
+ uint8_t *CurrentUnitData = nullptr;
+ std::atomic<size_t> CurrentUnitSize;
+ uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit.
+ bool RunningCB = false;
+
+ bool GracefulExitRequested = false;
+
+ size_t TotalNumberOfRuns = 0;
+ size_t NumberOfNewUnitsAdded = 0;
+
+ size_t LastCorpusUpdateRun = 0;
+
+ bool HasMoreMallocsThanFrees = false;
+ size_t NumberOfLeakDetectionAttempts = 0;
+
+ system_clock::time_point LastAllocatorPurgeAttemptTime = system_clock::now();
+
+ UserCallback CB;
+ InputCorpus &Corpus;
+ MutationDispatcher &MD;
+ FuzzingOptions Options;
+
+ system_clock::time_point ProcessStartTime = system_clock::now();
+ system_clock::time_point UnitStartTime, UnitStopTime;
+ long TimeOfLongestUnitInSeconds = 0;
+ long EpochOfLastReadOfOutputCorpus = 0;
+
+ size_t MaxInputLen = 0;
+ size_t MaxMutationLen = 0;
+ size_t TmpMaxMutationLen = 0;
+
+ Vector<uint32_t> UniqFeatureSetTmp;
+
+ // Need to know our own thread.
+ static thread_local bool IsMyThread;
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_INTERNAL_H
diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp
new file mode 100644
index 000000000000..5b451ca122d7
--- /dev/null
+++ b/lib/fuzzer/FuzzerLoop.cpp
@@ -0,0 +1,839 @@
+//===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Fuzzer's main loop.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerCorpus.h"
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include "FuzzerMutate.h"
+#include "FuzzerRandom.h"
+#include "FuzzerShmem.h"
+#include "FuzzerTracePC.h"
+#include <algorithm>
+#include <cstring>
+#include <memory>
+#include <mutex>
+#include <set>
+
+#if defined(__has_include)
+#if __has_include(<sanitizer / lsan_interface.h>)
+#include <sanitizer/lsan_interface.h>
+#endif
+#endif
+
+#define NO_SANITIZE_MEMORY
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#undef NO_SANITIZE_MEMORY
+#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+#endif
+#endif
+
+namespace fuzzer {
+static const size_t kMaxUnitSizeToPrint = 256;
+
+thread_local bool Fuzzer::IsMyThread;
+
+SharedMemoryRegion SMR;
+
+// Only one Fuzzer per process.
+static Fuzzer *F;
+
+// Leak detection is expensive, so we first check if there were more mallocs
+// than frees (using the sanitizer malloc hooks) and only then try to call lsan.
+struct MallocFreeTracer {
+ void Start(int TraceLevel) {
+ this->TraceLevel = TraceLevel;
+ if (TraceLevel)
+ Printf("MallocFreeTracer: START\n");
+ Mallocs = 0;
+ Frees = 0;
+ }
+ // Returns true if there were more mallocs than frees.
+ bool Stop() {
+ if (TraceLevel)
+ Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(),
+ Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT");
+ bool Result = Mallocs > Frees;
+ Mallocs = 0;
+ Frees = 0;
+ TraceLevel = 0;
+ return Result;
+ }
+ std::atomic<size_t> Mallocs;
+ std::atomic<size_t> Frees;
+ int TraceLevel = 0;
+
+ std::recursive_mutex TraceMutex;
+ bool TraceDisabled = false;
+};
+
+static MallocFreeTracer AllocTracer;
+
+// Locks printing and avoids nested hooks triggered from mallocs/frees in
+// sanitizer.
+class TraceLock {
+public:
+ TraceLock() : Lock(AllocTracer.TraceMutex) {
+ AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled;
+ }
+ ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; }
+
+ bool IsDisabled() const {
+ // This is already inverted value.
+ return !AllocTracer.TraceDisabled;
+ }
+
+private:
+ std::lock_guard<std::recursive_mutex> Lock;
+};
+
+ATTRIBUTE_NO_SANITIZE_MEMORY
+void MallocHook(const volatile void *ptr, size_t size) {
+ size_t N = AllocTracer.Mallocs++;
+ F->HandleMalloc(size);
+ if (int TraceLevel = AllocTracer.TraceLevel) {
+ TraceLock Lock;
+ if (Lock.IsDisabled())
+ return;
+ Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
+ if (TraceLevel >= 2 && EF)
+ EF->__sanitizer_print_stack_trace();
+ }
+}
+
+ATTRIBUTE_NO_SANITIZE_MEMORY
+void FreeHook(const volatile void *ptr) {
+ size_t N = AllocTracer.Frees++;
+ if (int TraceLevel = AllocTracer.TraceLevel) {
+ TraceLock Lock;
+ if (Lock.IsDisabled())
+ return;
+ Printf("FREE[%zd] %p\n", N, ptr);
+ if (TraceLevel >= 2 && EF)
+ EF->__sanitizer_print_stack_trace();
+ }
+}
+
+// Crash on a single malloc that exceeds the rss limit.
+void Fuzzer::HandleMalloc(size_t Size) {
+ if (!Options.MallocLimitMb || (Size >> 20) < (size_t)Options.MallocLimitMb)
+ return;
+ Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
+ Size);
+ Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
+ if (EF->__sanitizer_print_stack_trace)
+ EF->__sanitizer_print_stack_trace();
+ DumpCurrentUnit("oom-");
+ Printf("SUMMARY: libFuzzer: out-of-memory\n");
+ PrintFinalStats();
+ _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
+Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
+ FuzzingOptions Options)
+ : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
+ if (EF->__sanitizer_set_death_callback)
+ EF->__sanitizer_set_death_callback(StaticDeathCallback);
+ assert(!F);
+ F = this;
+ TPC.ResetMaps();
+ IsMyThread = true;
+ if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
+ EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
+ TPC.SetUseCounters(Options.UseCounters);
+ TPC.SetUseValueProfile(Options.UseValueProfile);
+ TPC.SetUseClangCoverage(Options.UseClangCoverage);
+
+ if (Options.Verbosity)
+ TPC.PrintModuleInfo();
+ if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
+ EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
+ MaxInputLen = MaxMutationLen = Options.MaxLen;
+ TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize());
+ AllocateCurrentUnitData();
+ CurrentUnitSize = 0;
+ memset(BaseSha1, 0, sizeof(BaseSha1));
+}
+
+Fuzzer::~Fuzzer() {}
+
+void Fuzzer::AllocateCurrentUnitData() {
+ if (CurrentUnitData || MaxInputLen == 0)
+ return;
+ CurrentUnitData = new uint8_t[MaxInputLen];
+}
+
+void Fuzzer::StaticDeathCallback() {
+ assert(F);
+ F->DeathCallback();
+}
+
+void Fuzzer::DumpCurrentUnit(const char *Prefix) {
+ if (!CurrentUnitData)
+ return; // Happens when running individual inputs.
+ MD.PrintMutationSequence();
+ Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
+ size_t UnitSize = CurrentUnitSize;
+ if (UnitSize <= kMaxUnitSizeToPrint) {
+ PrintHexArray(CurrentUnitData, UnitSize, "\n");
+ PrintASCII(CurrentUnitData, UnitSize, "\n");
+ }
+ WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
+ Prefix);
+}
+
+NO_SANITIZE_MEMORY
+void Fuzzer::DeathCallback() {
+ DumpCurrentUnit("crash-");
+ PrintFinalStats();
+}
+
+void Fuzzer::StaticAlarmCallback() {
+ assert(F);
+ F->AlarmCallback();
+}
+
+void Fuzzer::StaticCrashSignalCallback() {
+ assert(F);
+ F->CrashCallback();
+}
+
+void Fuzzer::StaticExitCallback() {
+ assert(F);
+ F->ExitCallback();
+}
+
+void Fuzzer::StaticInterruptCallback() {
+ assert(F);
+ F->InterruptCallback();
+}
+
+void Fuzzer::StaticGracefulExitCallback() {
+ assert(F);
+ F->GracefulExitRequested = true;
+ Printf("INFO: signal received, trying to exit gracefully\n");
+}
+
+void Fuzzer::StaticFileSizeExceedCallback() {
+ Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
+ exit(1);
+}
+
+void Fuzzer::CrashCallback() {
+ Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
+ if (EF->__sanitizer_print_stack_trace)
+ EF->__sanitizer_print_stack_trace();
+ Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
+ " Combine libFuzzer with AddressSanitizer or similar for better "
+ "crash reports.\n");
+ Printf("SUMMARY: libFuzzer: deadly signal\n");
+ DumpCurrentUnit("crash-");
+ PrintFinalStats();
+ _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
+void Fuzzer::ExitCallback() {
+ if (!RunningCB)
+ return; // This exit did not come from the user callback
+ Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
+ if (EF->__sanitizer_print_stack_trace)
+ EF->__sanitizer_print_stack_trace();
+ Printf("SUMMARY: libFuzzer: fuzz target exited\n");
+ DumpCurrentUnit("crash-");
+ PrintFinalStats();
+ _Exit(Options.ErrorExitCode);
+}
+
+void Fuzzer::MaybeExitGracefully() {
+ if (!GracefulExitRequested) return;
+ Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
+ PrintFinalStats();
+ _Exit(0);
+}
+
+void Fuzzer::InterruptCallback() {
+ Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
+ PrintFinalStats();
+ _Exit(0); // Stop right now, don't perform any at-exit actions.
+}
+
+NO_SANITIZE_MEMORY
+void Fuzzer::AlarmCallback() {
+ assert(Options.UnitTimeoutSec > 0);
+ // In Windows Alarm callback is executed by a different thread.
+#if !LIBFUZZER_WINDOWS
+ if (!InFuzzingThread())
+ return;
+#endif
+ if (!RunningCB)
+ return; // We have not started running units yet.
+ size_t Seconds =
+ duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
+ if (Seconds == 0)
+ return;
+ if (Options.Verbosity >= 2)
+ Printf("AlarmCallback %zd\n", Seconds);
+ if (Seconds >= (size_t)Options.UnitTimeoutSec) {
+ Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
+ Printf(" and the timeout value is %d (use -timeout=N to change)\n",
+ Options.UnitTimeoutSec);
+ DumpCurrentUnit("timeout-");
+ Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
+ Seconds);
+ if (EF->__sanitizer_print_stack_trace)
+ EF->__sanitizer_print_stack_trace();
+ Printf("SUMMARY: libFuzzer: timeout\n");
+ PrintFinalStats();
+ _Exit(Options.TimeoutExitCode); // Stop right now.
+ }
+}
+
+void Fuzzer::RssLimitCallback() {
+ Printf(
+ "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
+ GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
+ Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
+ if (EF->__sanitizer_print_memory_profile)
+ EF->__sanitizer_print_memory_profile(95, 8);
+ DumpCurrentUnit("oom-");
+ Printf("SUMMARY: libFuzzer: out-of-memory\n");
+ PrintFinalStats();
+ _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
+void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
+ size_t ExecPerSec = execPerSec();
+ if (!Options.Verbosity)
+ return;
+ Printf("#%zd\t%s", TotalNumberOfRuns, Where);
+ if (size_t N = TPC.GetTotalPCCoverage())
+ Printf(" cov: %zd", N);
+ if (size_t N = Corpus.NumFeatures())
+ Printf(" ft: %zd", N);
+ if (!Corpus.empty()) {
+ Printf(" corp: %zd", Corpus.NumActiveUnits());
+ if (size_t N = Corpus.SizeInBytes()) {
+ if (N < (1 << 14))
+ Printf("/%zdb", N);
+ else if (N < (1 << 24))
+ Printf("/%zdKb", N >> 10);
+ else
+ Printf("/%zdMb", N >> 20);
+ }
+ }
+ if (Units)
+ Printf(" units: %zd", Units);
+
+ Printf(" exec/s: %zd", ExecPerSec);
+ Printf(" rss: %zdMb", GetPeakRSSMb());
+ Printf("%s", End);
+}
+
+void Fuzzer::PrintFinalStats() {
+ if (Options.PrintCoverage)
+ TPC.PrintCoverage();
+ if (Options.DumpCoverage)
+ TPC.DumpCoverage();
+ if (Options.PrintCorpusStats)
+ Corpus.PrintStats();
+ if (!Options.PrintFinalStats)
+ return;
+ size_t ExecPerSec = execPerSec();
+ Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
+ Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec);
+ Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded);
+ Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds);
+ Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb());
+}
+
+void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
+ assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
+ assert(MaxInputLen);
+ this->MaxInputLen = MaxInputLen;
+ this->MaxMutationLen = MaxInputLen;
+ AllocateCurrentUnitData();
+ Printf("INFO: -max_len is not provided; "
+ "libFuzzer will not generate inputs larger than %zd bytes\n",
+ MaxInputLen);
+}
+
+void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
+ assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
+ this->MaxMutationLen = MaxMutationLen;
+}
+
+void Fuzzer::CheckExitOnSrcPosOrItem() {
+ if (!Options.ExitOnSrcPos.empty()) {
+ static auto *PCsSet = new Set<uintptr_t>;
+ auto HandlePC = [&](uintptr_t PC) {
+ if (!PCsSet->insert(PC).second)
+ return;
+ std::string Descr = DescribePC("%F %L", PC + 1);
+ if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
+ Printf("INFO: found line matching '%s', exiting.\n",
+ Options.ExitOnSrcPos.c_str());
+ _Exit(0);
+ }
+ };
+ TPC.ForEachObservedPC(HandlePC);
+ }
+ if (!Options.ExitOnItem.empty()) {
+ if (Corpus.HasUnit(Options.ExitOnItem)) {
+ Printf("INFO: found item with checksum '%s', exiting.\n",
+ Options.ExitOnItem.c_str());
+ _Exit(0);
+ }
+ }
+}
+
+void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
+ if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec)
+ return;
+ Vector<Unit> AdditionalCorpus;
+ ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
+ &EpochOfLastReadOfOutputCorpus, MaxSize,
+ /*ExitOnError*/ false);
+ if (Options.Verbosity >= 2)
+ Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
+ bool Reloaded = false;
+ for (auto &U : AdditionalCorpus) {
+ if (U.size() > MaxSize)
+ U.resize(MaxSize);
+ if (!Corpus.HasUnit(U)) {
+ if (RunOne(U.data(), U.size())) {
+ CheckExitOnSrcPosOrItem();
+ Reloaded = true;
+ }
+ }
+ }
+ if (Reloaded)
+ PrintStats("RELOAD");
+}
+
+void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
+ auto TimeOfUnit =
+ duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
+ if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
+ secondsSinceProcessStartUp() >= 2)
+ PrintStats("pulse ");
+ if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 &&
+ TimeOfUnit >= Options.ReportSlowUnits) {
+ TimeOfLongestUnitInSeconds = TimeOfUnit;
+ Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
+ WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
+ }
+}
+
+bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
+ InputInfo *II, bool *FoundUniqFeatures) {
+ if (!Size)
+ return false;
+
+ ExecuteCallback(Data, Size);
+
+ UniqFeatureSetTmp.clear();
+ size_t FoundUniqFeaturesOfII = 0;
+ size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
+ TPC.CollectFeatures([&](size_t Feature) {
+ if (Options.UseFeatureFrequency)
+ Corpus.UpdateFeatureFrequency(Feature);
+ if (Corpus.AddFeature(Feature, Size, Options.Shrink))
+ UniqFeatureSetTmp.push_back(Feature);
+ if (Options.ReduceInputs && II)
+ if (std::binary_search(II->UniqFeatureSet.begin(),
+ II->UniqFeatureSet.end(), Feature))
+ FoundUniqFeaturesOfII++;
+ });
+ if (FoundUniqFeatures)
+ *FoundUniqFeatures = FoundUniqFeaturesOfII;
+ PrintPulseAndReportSlowInput(Data, Size);
+ size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
+ if (NumNewFeatures) {
+ TPC.UpdateObservedPCs();
+ Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
+ UniqFeatureSetTmp);
+ return true;
+ }
+ if (II && FoundUniqFeaturesOfII &&
+ FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&
+ II->U.size() > Size) {
+ Corpus.Replace(II, {Data, Data + Size});
+ return true;
+ }
+ return false;
+}
+
+size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
+ assert(InFuzzingThread());
+ *Data = CurrentUnitData;
+ return CurrentUnitSize;
+}
+
+void Fuzzer::CrashOnOverwrittenData() {
+ Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n",
+ GetPid());
+ DumpCurrentUnit("crash-");
+ Printf("SUMMARY: libFuzzer: out-of-memory\n");
+ _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
+// Compare two arrays, but not all bytes if the arrays are large.
+static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) {
+ const size_t Limit = 64;
+ if (Size <= 64)
+ return !memcmp(A, B, Size);
+ // Compare first and last Limit/2 bytes.
+ return !memcmp(A, B, Limit / 2) &&
+ !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
+}
+
+void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
+ TPC.RecordInitialStack();
+ TotalNumberOfRuns++;
+ assert(InFuzzingThread());
+ if (SMR.IsClient())
+ SMR.WriteByteArray(Data, Size);
+ // We copy the contents of Unit into a separate heap buffer
+ // so that we reliably find buffer overflows in it.
+ uint8_t *DataCopy = new uint8_t[Size];
+ memcpy(DataCopy, Data, Size);
+ if (CurrentUnitData && CurrentUnitData != Data)
+ memcpy(CurrentUnitData, Data, Size);
+ CurrentUnitSize = Size;
+ AllocTracer.Start(Options.TraceMalloc);
+ UnitStartTime = system_clock::now();
+ TPC.ResetMaps();
+ RunningCB = true;
+ int Res = CB(DataCopy, Size);
+ RunningCB = false;
+ UnitStopTime = system_clock::now();
+ (void)Res;
+ assert(Res == 0);
+ HasMoreMallocsThanFrees = AllocTracer.Stop();
+ if (!LooseMemeq(DataCopy, Data, Size))
+ CrashOnOverwrittenData();
+ CurrentUnitSize = 0;
+ delete[] DataCopy;
+}
+
+void Fuzzer::WriteToOutputCorpus(const Unit &U) {
+ if (Options.OnlyASCII)
+ assert(IsASCII(U));
+ if (Options.OutputCorpus.empty())
+ return;
+ std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
+ WriteToFile(U, Path);
+ if (Options.Verbosity >= 2)
+ Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
+}
+
+void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
+ if (!Options.SaveArtifacts)
+ return;
+ std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
+ if (!Options.ExactArtifactPath.empty())
+ Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
+ WriteToFile(U, Path);
+ Printf("artifact_prefix='%s'; Test unit written to %s\n",
+ Options.ArtifactPrefix.c_str(), Path.c_str());
+ if (U.size() <= kMaxUnitSizeToPrint)
+ Printf("Base64: %s\n", Base64(U).c_str());
+}
+
+void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
+ if (!Options.PrintNEW)
+ return;
+ PrintStats(Text, "");
+ if (Options.Verbosity) {
+ Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
+ MD.PrintMutationSequence();
+ Printf("\n");
+ }
+}
+
+void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
+ II->NumSuccessfullMutations++;
+ MD.RecordSuccessfulMutationSequence();
+ PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW ");
+ WriteToOutputCorpus(U);
+ NumberOfNewUnitsAdded++;
+ CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
+ LastCorpusUpdateRun = TotalNumberOfRuns;
+}
+
+// Tries detecting a memory leak on the particular input that we have just
+// executed before calling this function.
+void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
+ bool DuringInitialCorpusExecution) {
+ if (!HasMoreMallocsThanFrees)
+ return; // mallocs==frees, a leak is unlikely.
+ if (!Options.DetectLeaks)
+ return;
+ if (!DuringInitialCorpusExecution &&
+ TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+ return;
+ if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
+ !(EF->__lsan_do_recoverable_leak_check))
+ return; // No lsan.
+ // Run the target once again, but with lsan disabled so that if there is
+ // a real leak we do not report it twice.
+ EF->__lsan_disable();
+ ExecuteCallback(Data, Size);
+ EF->__lsan_enable();
+ if (!HasMoreMallocsThanFrees)
+ return; // a leak is unlikely.
+ if (NumberOfLeakDetectionAttempts++ > 1000) {
+ Options.DetectLeaks = false;
+ Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
+ " Most likely the target function accumulates allocated\n"
+ " memory in a global state w/o actually leaking it.\n"
+ " You may try running this binary with -trace_malloc=[12]"
+ " to get a trace of mallocs and frees.\n"
+ " If LeakSanitizer is enabled in this process it will still\n"
+ " run on the process shutdown.\n");
+ return;
+ }
+ // Now perform the actual lsan pass. This is expensive and we must ensure
+ // we don't call it too often.
+ if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
+ if (DuringInitialCorpusExecution)
+ Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
+ Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
+ CurrentUnitSize = Size;
+ DumpCurrentUnit("leak-");
+ PrintFinalStats();
+ _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
+ }
+}
+
+void Fuzzer::MutateAndTestOne() {
+ MD.StartMutationSequence();
+
+ auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
+ if (Options.UseFeatureFrequency)
+ Corpus.UpdateFeatureFrequencyScore(&II);
+ const auto &U = II.U;
+ memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
+ assert(CurrentUnitData);
+ size_t Size = U.size();
+ assert(Size <= MaxInputLen && "Oversized Unit");
+ memcpy(CurrentUnitData, U.data(), Size);
+
+ assert(MaxMutationLen > 0);
+
+ size_t CurrentMaxMutationLen =
+ Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen));
+ assert(CurrentMaxMutationLen > 0);
+
+ for (int i = 0; i < Options.MutateDepth; i++) {
+ if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+ break;
+ MaybeExitGracefully();
+ size_t NewSize = 0;
+ NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
+ assert(NewSize > 0 && "Mutator returned empty unit");
+ assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");
+ Size = NewSize;
+ II.NumExecutedMutations++;
+
+ bool FoundUniqFeatures = false;
+ bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II,
+ &FoundUniqFeatures);
+ TryDetectingAMemoryLeak(CurrentUnitData, Size,
+ /*DuringInitialCorpusExecution*/ false);
+ if (NewCov) {
+ ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
+ break; // We will mutate this input more in the next rounds.
+ }
+ if (Options.ReduceDepth && !FoundUniqFeatures)
+ break;
+ }
+}
+
+void Fuzzer::PurgeAllocator() {
+ if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator)
+ return;
+ if (duration_cast<seconds>(system_clock::now() -
+ LastAllocatorPurgeAttemptTime)
+ .count() < Options.PurgeAllocatorIntervalSec)
+ return;
+
+ if (Options.RssLimitMb <= 0 ||
+ GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2)
+ EF->__sanitizer_purge_allocator();
+
+ LastAllocatorPurgeAttemptTime = system_clock::now();
+}
+
+void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) {
+ const size_t kMaxSaneLen = 1 << 20;
+ const size_t kMinDefaultLen = 4096;
+ Vector<SizedFile> SizedFiles;
+ size_t MaxSize = 0;
+ size_t MinSize = -1;
+ size_t TotalSize = 0;
+ size_t LastNumFiles = 0;
+ for (auto &Dir : CorpusDirs) {
+ GetSizedFilesFromDir(Dir, &SizedFiles);
+ Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles,
+ Dir.c_str());
+ LastNumFiles = SizedFiles.size();
+ }
+ for (auto &File : SizedFiles) {
+ MaxSize = Max(File.Size, MaxSize);
+ MinSize = Min(File.Size, MinSize);
+ TotalSize += File.Size;
+ }
+ if (Options.MaxLen == 0)
+ SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen));
+ assert(MaxInputLen > 0);
+
+ // Test the callback with empty input and never try it again.
+ uint8_t dummy = 0;
+ ExecuteCallback(&dummy, 0);
+
+ if (SizedFiles.empty()) {
+ Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
+ Unit U({'\n'}); // Valid ASCII input.
+ RunOne(U.data(), U.size());
+ } else {
+ Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
+ " rss: %zdMb\n",
+ SizedFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb());
+ if (Options.ShuffleAtStartUp)
+ std::shuffle(SizedFiles.begin(), SizedFiles.end(), MD.GetRand());
+
+ if (Options.PreferSmall) {
+ std::stable_sort(SizedFiles.begin(), SizedFiles.end());
+ assert(SizedFiles.front().Size <= SizedFiles.back().Size);
+ }
+
+ // Load and execute inputs one by one.
+ for (auto &SF : SizedFiles) {
+ auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false);
+ assert(U.size() <= MaxInputLen);
+ RunOne(U.data(), U.size());
+ CheckExitOnSrcPosOrItem();
+ TryDetectingAMemoryLeak(U.data(), U.size(),
+ /*DuringInitialCorpusExecution*/ true);
+ }
+ }
+
+ PrintStats("INITED");
+ if (Corpus.empty()) {
+ Printf("ERROR: no interesting inputs were found. "
+ "Is the code instrumented for coverage? Exiting.\n");
+ exit(1);
+ }
+}
+
+void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) {
+ ReadAndExecuteSeedCorpora(CorpusDirs);
+ TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
+ TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
+ system_clock::time_point LastCorpusReload = system_clock::now();
+ if (Options.DoCrossOver)
+ MD.SetCorpus(&Corpus);
+ while (true) {
+ auto Now = system_clock::now();
+ if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
+ Options.ReloadIntervalSec) {
+ RereadOutputCorpus(MaxInputLen);
+ LastCorpusReload = system_clock::now();
+ }
+ if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+ break;
+ if (TimedOut())
+ break;
+
+ // Update TmpMaxMutationLen
+ if (Options.ExperimentalLenControl) {
+ if (TmpMaxMutationLen < MaxMutationLen &&
+ TotalNumberOfRuns - LastCorpusUpdateRun >
+ Options.ExperimentalLenControl * Log(TmpMaxMutationLen)) {
+ TmpMaxMutationLen =
+ Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen));
+ if (TmpMaxMutationLen <= MaxMutationLen)
+ Printf("#%zd\tTEMP_MAX_LEN: %zd (%zd %zd)\n", TotalNumberOfRuns,
+ TmpMaxMutationLen, Options.ExperimentalLenControl,
+ LastCorpusUpdateRun);
+ LastCorpusUpdateRun = TotalNumberOfRuns;
+ }
+ } else {
+ TmpMaxMutationLen = MaxMutationLen;
+ }
+
+ // Perform several mutations and runs.
+ MutateAndTestOne();
+
+ PurgeAllocator();
+ }
+
+ PrintStats("DONE ", "\n");
+ MD.PrintRecommendedDictionary();
+}
+
+void Fuzzer::MinimizeCrashLoop(const Unit &U) {
+ if (U.size() <= 1)
+ return;
+ while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
+ MD.StartMutationSequence();
+ memcpy(CurrentUnitData, U.data(), U.size());
+ for (int i = 0; i < Options.MutateDepth; i++) {
+ size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
+ assert(NewSize > 0 && NewSize <= MaxMutationLen);
+ ExecuteCallback(CurrentUnitData, NewSize);
+ PrintPulseAndReportSlowInput(CurrentUnitData, NewSize);
+ TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
+ /*DuringInitialCorpusExecution*/ false);
+ }
+ }
+}
+
+void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) {
+ if (SMR.IsServer()) {
+ SMR.WriteByteArray(Data, Size);
+ } else if (SMR.IsClient()) {
+ SMR.PostClient();
+ SMR.WaitServer();
+ size_t OtherSize = SMR.ReadByteArraySize();
+ uint8_t *OtherData = SMR.GetByteArray();
+ if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) {
+ size_t i = 0;
+ for (i = 0; i < Min(Size, OtherSize); i++)
+ if (Data[i] != OtherData[i])
+ break;
+ Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; "
+ "offset %zd\n",
+ GetPid(), Size, OtherSize, i);
+ DumpCurrentUnit("mismatch-");
+ Printf("SUMMARY: libFuzzer: equivalence-mismatch\n");
+ PrintFinalStats();
+ _Exit(Options.ErrorExitCode);
+ }
+ }
+}
+
+} // namespace fuzzer
+
+extern "C" {
+
+size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+ assert(fuzzer::F);
+ return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
+}
+
+// Experimental
+void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {
+ assert(fuzzer::F);
+ fuzzer::F->AnnounceOutput(Data, Size);
+}
+} // extern "C"
diff --git a/lib/fuzzer/FuzzerMain.cpp b/lib/fuzzer/FuzzerMain.cpp
new file mode 100644
index 000000000000..af8657200be2
--- /dev/null
+++ b/lib/fuzzer/FuzzerMain.cpp
@@ -0,0 +1,21 @@
+//===- FuzzerMain.cpp - main() function and flags -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// main() and flags.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDefs.h"
+
+extern "C" {
+// This function should be defined by the user.
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+} // extern "C"
+
+int main(int argc, char **argv) {
+ return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput);
+}
diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp
new file mode 100644
index 000000000000..5f3052a39c16
--- /dev/null
+++ b/lib/fuzzer/FuzzerMerge.cpp
@@ -0,0 +1,390 @@
+//===- FuzzerMerge.cpp - merging corpora ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Merging corpora.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerCommand.h"
+#include "FuzzerMerge.h"
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include "FuzzerTracePC.h"
+#include "FuzzerUtil.h"
+
+#include <fstream>
+#include <iterator>
+#include <set>
+#include <sstream>
+
+namespace fuzzer {
+
+bool Merger::Parse(const std::string &Str, bool ParseCoverage) {
+ std::istringstream SS(Str);
+ return Parse(SS, ParseCoverage);
+}
+
+void Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) {
+ if (!Parse(IS, ParseCoverage)) {
+ Printf("MERGE: failed to parse the control file (unexpected error)\n");
+ exit(1);
+ }
+}
+
+// The control file example:
+//
+// 3 # The number of inputs
+// 1 # The number of inputs in the first corpus, <= the previous number
+// file0
+// file1
+// file2 # One file name per line.
+// STARTED 0 123 # FileID, file size
+// DONE 0 1 4 6 8 # FileID COV1 COV2 ...
+// STARTED 1 456 # If DONE is missing, the input crashed while processing.
+// STARTED 2 567
+// DONE 2 8 9
+bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
+ LastFailure.clear();
+ std::string Line;
+
+ // Parse NumFiles.
+ if (!std::getline(IS, Line, '\n')) return false;
+ std::istringstream L1(Line);
+ size_t NumFiles = 0;
+ L1 >> NumFiles;
+ if (NumFiles == 0 || NumFiles > 10000000) return false;
+
+ // Parse NumFilesInFirstCorpus.
+ if (!std::getline(IS, Line, '\n')) return false;
+ std::istringstream L2(Line);
+ NumFilesInFirstCorpus = NumFiles + 1;
+ L2 >> NumFilesInFirstCorpus;
+ if (NumFilesInFirstCorpus > NumFiles) return false;
+
+ // Parse file names.
+ Files.resize(NumFiles);
+ for (size_t i = 0; i < NumFiles; i++)
+ if (!std::getline(IS, Files[i].Name, '\n'))
+ return false;
+
+ // Parse STARTED and DONE lines.
+ size_t ExpectedStartMarker = 0;
+ const size_t kInvalidStartMarker = -1;
+ size_t LastSeenStartMarker = kInvalidStartMarker;
+ Vector<uint32_t> TmpFeatures;
+ while (std::getline(IS, Line, '\n')) {
+ std::istringstream ISS1(Line);
+ std::string Marker;
+ size_t N;
+ ISS1 >> Marker;
+ ISS1 >> N;
+ if (Marker == "STARTED") {
+ // STARTED FILE_ID FILE_SIZE
+ if (ExpectedStartMarker != N)
+ return false;
+ ISS1 >> Files[ExpectedStartMarker].Size;
+ LastSeenStartMarker = ExpectedStartMarker;
+ assert(ExpectedStartMarker < Files.size());
+ ExpectedStartMarker++;
+ } else if (Marker == "DONE") {
+ // DONE FILE_ID COV1 COV2 COV3 ...
+ size_t CurrentFileIdx = N;
+ if (CurrentFileIdx != LastSeenStartMarker)
+ return false;
+ LastSeenStartMarker = kInvalidStartMarker;
+ if (ParseCoverage) {
+ TmpFeatures.clear(); // use a vector from outer scope to avoid resizes.
+ while (ISS1 >> std::hex >> N)
+ TmpFeatures.push_back(N);
+ std::sort(TmpFeatures.begin(), TmpFeatures.end());
+ Files[CurrentFileIdx].Features = TmpFeatures;
+ }
+ } else {
+ return false;
+ }
+ }
+ if (LastSeenStartMarker != kInvalidStartMarker)
+ LastFailure = Files[LastSeenStartMarker].Name;
+
+ FirstNotProcessedFile = ExpectedStartMarker;
+ return true;
+}
+
+size_t Merger::ApproximateMemoryConsumption() const {
+ size_t Res = 0;
+ for (const auto &F: Files)
+ Res += sizeof(F) + F.Features.size() * sizeof(F.Features[0]);
+ return Res;
+}
+
+// Decides which files need to be merged (add thost to NewFiles).
+// Returns the number of new features added.
+size_t Merger::Merge(const Set<uint32_t> &InitialFeatures,
+ Vector<std::string> *NewFiles) {
+ NewFiles->clear();
+ assert(NumFilesInFirstCorpus <= Files.size());
+ Set<uint32_t> AllFeatures(InitialFeatures);
+
+ // What features are in the initial corpus?
+ for (size_t i = 0; i < NumFilesInFirstCorpus; i++) {
+ auto &Cur = Files[i].Features;
+ AllFeatures.insert(Cur.begin(), Cur.end());
+ }
+ size_t InitialNumFeatures = AllFeatures.size();
+
+ // Remove all features that we already know from all other inputs.
+ for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
+ auto &Cur = Files[i].Features;
+ Vector<uint32_t> Tmp;
+ std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(),
+ AllFeatures.end(), std::inserter(Tmp, Tmp.begin()));
+ Cur.swap(Tmp);
+ }
+
+ // Sort. Give preference to
+ // * smaller files
+ // * files with more features.
+ std::sort(Files.begin() + NumFilesInFirstCorpus, Files.end(),
+ [&](const MergeFileInfo &a, const MergeFileInfo &b) -> bool {
+ if (a.Size != b.Size)
+ return a.Size < b.Size;
+ return a.Features.size() > b.Features.size();
+ });
+
+ // One greedy pass: add the file's features to AllFeatures.
+ // If new features were added, add this file to NewFiles.
+ for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
+ auto &Cur = Files[i].Features;
+ // Printf("%s -> sz %zd ft %zd\n", Files[i].Name.c_str(),
+ // Files[i].Size, Cur.size());
+ size_t OldSize = AllFeatures.size();
+ AllFeatures.insert(Cur.begin(), Cur.end());
+ if (AllFeatures.size() > OldSize)
+ NewFiles->push_back(Files[i].Name);
+ }
+ return AllFeatures.size() - InitialNumFeatures;
+}
+
+void Merger::PrintSummary(std::ostream &OS) {
+ for (auto &File : Files) {
+ OS << std::hex;
+ OS << File.Name << " size: " << File.Size << " features: ";
+ for (auto Feature : File.Features)
+ OS << " " << Feature;
+ OS << "\n";
+ }
+}
+
+Set<uint32_t> Merger::AllFeatures() const {
+ Set<uint32_t> S;
+ for (auto &File : Files)
+ S.insert(File.Features.begin(), File.Features.end());
+ return S;
+}
+
+Set<uint32_t> Merger::ParseSummary(std::istream &IS) {
+ std::string Line, Tmp;
+ Set<uint32_t> Res;
+ while (std::getline(IS, Line, '\n')) {
+ size_t N;
+ std::istringstream ISS1(Line);
+ ISS1 >> Tmp; // Name
+ ISS1 >> Tmp; // size:
+ assert(Tmp == "size:" && "Corrupt summary file");
+ ISS1 >> std::hex;
+ ISS1 >> N; // File Size
+ ISS1 >> Tmp; // features:
+ assert(Tmp == "features:" && "Corrupt summary file");
+ while (ISS1 >> std::hex >> N)
+ Res.insert(N);
+ }
+ return Res;
+}
+
+// Inner process. May crash if the target crashes.
+void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
+ Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str());
+ Merger M;
+ std::ifstream IF(CFPath);
+ M.ParseOrExit(IF, false);
+ IF.close();
+ if (!M.LastFailure.empty())
+ Printf("MERGE-INNER: '%s' caused a failure at the previous merge step\n",
+ M.LastFailure.c_str());
+
+ Printf("MERGE-INNER: %zd total files;"
+ " %zd processed earlier; will process %zd files now\n",
+ M.Files.size(), M.FirstNotProcessedFile,
+ M.Files.size() - M.FirstNotProcessedFile);
+
+ std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app);
+ Set<size_t> AllFeatures;
+ for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) {
+ MaybeExitGracefully();
+ auto U = FileToVector(M.Files[i].Name);
+ if (U.size() > MaxInputLen) {
+ U.resize(MaxInputLen);
+ U.shrink_to_fit();
+ }
+ std::ostringstream StartedLine;
+ // Write the pre-run marker.
+ OF << "STARTED " << std::dec << i << " " << U.size() << "\n";
+ OF.flush(); // Flush is important since Command::Execute may crash.
+ // Run.
+ TPC.ResetMaps();
+ ExecuteCallback(U.data(), U.size());
+ // Collect coverage. We are iterating over the files in this order:
+ // * First, files in the initial corpus ordered by size, smallest first.
+ // * Then, all other files, smallest first.
+ // So it makes no sense to record all features for all files, instead we
+ // only record features that were not seen before.
+ Set<size_t> UniqFeatures;
+ TPC.CollectFeatures([&](size_t Feature) {
+ if (AllFeatures.insert(Feature).second)
+ UniqFeatures.insert(Feature);
+ });
+ // Show stats.
+ if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)))
+ PrintStats("pulse ");
+ // Write the post-run marker and the coverage.
+ OF << "DONE " << i;
+ for (size_t F : UniqFeatures)
+ OF << " " << std::hex << F;
+ OF << "\n";
+ OF.flush();
+ }
+}
+
+static void WriteNewControlFile(const std::string &CFPath,
+ const Vector<SizedFile> &AllFiles,
+ size_t NumFilesInFirstCorpus) {
+ RemoveFile(CFPath);
+ std::ofstream ControlFile(CFPath);
+ ControlFile << AllFiles.size() << "\n";
+ ControlFile << NumFilesInFirstCorpus << "\n";
+ for (auto &SF: AllFiles)
+ ControlFile << SF.File << "\n";
+ if (!ControlFile) {
+ Printf("MERGE-OUTER: failed to write to the control file: %s\n",
+ CFPath.c_str());
+ exit(1);
+ }
+}
+
+// Outer process. Does not call the target code and thus sohuld not fail.
+void Fuzzer::CrashResistantMerge(const Vector<std::string> &Args,
+ const Vector<std::string> &Corpora,
+ const char *CoverageSummaryInputPathOrNull,
+ const char *CoverageSummaryOutputPathOrNull,
+ const char *MergeControlFilePathOrNull) {
+ if (Corpora.size() <= 1) {
+ Printf("Merge requires two or more corpus dirs\n");
+ return;
+ }
+ auto CFPath =
+ MergeControlFilePathOrNull
+ ? MergeControlFilePathOrNull
+ : DirPlusFile(TmpDir(),
+ "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
+
+ size_t NumAttempts = 0;
+ if (MergeControlFilePathOrNull && FileSize(MergeControlFilePathOrNull)) {
+ Printf("MERGE-OUTER: non-empty control file provided: '%s'\n",
+ MergeControlFilePathOrNull);
+ Merger M;
+ std::ifstream IF(MergeControlFilePathOrNull);
+ if (M.Parse(IF, /*ParseCoverage=*/false)) {
+ Printf("MERGE-OUTER: control file ok, %zd files total,"
+ " first not processed file %zd\n",
+ M.Files.size(), M.FirstNotProcessedFile);
+ if (!M.LastFailure.empty())
+ Printf("MERGE-OUTER: '%s' will be skipped as unlucky "
+ "(merge has stumbled on it the last time)\n",
+ M.LastFailure.c_str());
+ if (M.FirstNotProcessedFile >= M.Files.size()) {
+ Printf("MERGE-OUTER: nothing to do, merge has been completed before\n");
+ exit(0);
+ }
+
+ NumAttempts = M.Files.size() - M.FirstNotProcessedFile;
+ } else {
+ Printf("MERGE-OUTER: bad control file, will overwrite it\n");
+ }
+ }
+
+ if (!NumAttempts) {
+ // The supplied control file is empty or bad, create a fresh one.
+ Vector<SizedFile> AllFiles;
+ GetSizedFilesFromDir(Corpora[0], &AllFiles);
+ size_t NumFilesInFirstCorpus = AllFiles.size();
+ std::sort(AllFiles.begin(), AllFiles.end());
+ for (size_t i = 1; i < Corpora.size(); i++)
+ GetSizedFilesFromDir(Corpora[i], &AllFiles);
+ std::sort(AllFiles.begin() + NumFilesInFirstCorpus, AllFiles.end());
+ Printf("MERGE-OUTER: %zd files, %zd in the initial corpus\n",
+ AllFiles.size(), NumFilesInFirstCorpus);
+ WriteNewControlFile(CFPath, AllFiles, NumFilesInFirstCorpus);
+ NumAttempts = AllFiles.size();
+ }
+
+ // Execute the inner process until it passes.
+ // Every inner process should execute at least one input.
+ Command BaseCmd(Args);
+ BaseCmd.removeFlag("merge");
+ bool Success = false;
+ for (size_t Attempt = 1; Attempt <= NumAttempts; Attempt++) {
+ MaybeExitGracefully();
+ Printf("MERGE-OUTER: attempt %zd\n", Attempt);
+ Command Cmd(BaseCmd);
+ Cmd.addFlag("merge_control_file", CFPath);
+ Cmd.addFlag("merge_inner", "1");
+ auto ExitCode = ExecuteCommand(Cmd);
+ if (!ExitCode) {
+ Printf("MERGE-OUTER: succesfull in %zd attempt(s)\n", Attempt);
+ Success = true;
+ break;
+ }
+ }
+ if (!Success) {
+ Printf("MERGE-OUTER: zero succesfull attempts, exiting\n");
+ exit(1);
+ }
+ // Read the control file and do the merge.
+ Merger M;
+ std::ifstream IF(CFPath);
+ IF.seekg(0, IF.end);
+ Printf("MERGE-OUTER: the control file has %zd bytes\n", (size_t)IF.tellg());
+ IF.seekg(0, IF.beg);
+ M.ParseOrExit(IF, true);
+ IF.close();
+ Printf("MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n",
+ M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb());
+ if (CoverageSummaryOutputPathOrNull) {
+ Printf("MERGE-OUTER: writing coverage summary for %zd files to %s\n",
+ M.Files.size(), CoverageSummaryOutputPathOrNull);
+ std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull);
+ M.PrintSummary(SummaryOut);
+ }
+ Vector<std::string> NewFiles;
+ Set<uint32_t> InitialFeatures;
+ if (CoverageSummaryInputPathOrNull) {
+ std::ifstream SummaryIn(CoverageSummaryInputPathOrNull);
+ InitialFeatures = M.ParseSummary(SummaryIn);
+ Printf("MERGE-OUTER: coverage summary loaded from %s, %zd features found\n",
+ CoverageSummaryInputPathOrNull, InitialFeatures.size());
+ }
+ size_t NumNewFeatures = M.Merge(InitialFeatures, &NewFiles);
+ Printf("MERGE-OUTER: %zd new files with %zd new features added\n",
+ NewFiles.size(), NumNewFeatures);
+ for (auto &F: NewFiles)
+ WriteToOutputCorpus(FileToVector(F, MaxInputLen));
+ // We are done, delete the control file if it was a temporary one.
+ if (!MergeControlFilePathOrNull)
+ RemoveFile(CFPath);
+}
+
+} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerMerge.h b/lib/fuzzer/FuzzerMerge.h
new file mode 100644
index 000000000000..e54885a1ebae
--- /dev/null
+++ b/lib/fuzzer/FuzzerMerge.h
@@ -0,0 +1,80 @@
+//===- FuzzerMerge.h - merging corpa ----------------------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Merging Corpora.
+//
+// The task:
+// Take the existing corpus (possibly empty) and merge new inputs into
+// it so that only inputs with new coverage ('features') are added.
+// The process should tolerate the crashes, OOMs, leaks, etc.
+//
+// Algorithm:
+// The outter process collects the set of files and writes their names
+// into a temporary "control" file, then repeatedly launches the inner
+// process until all inputs are processed.
+// The outer process does not actually execute the target code.
+//
+// The inner process reads the control file and sees a) list of all the inputs
+// and b) the last processed input. Then it starts processing the inputs one
+// by one. Before processing every input it writes one line to control file:
+// STARTED INPUT_ID INPUT_SIZE
+// After processing an input it write another line:
+// DONE INPUT_ID Feature1 Feature2 Feature3 ...
+// If a crash happens while processing an input the last line in the control
+// file will be "STARTED INPUT_ID" and so the next process will know
+// where to resume.
+//
+// Once all inputs are processed by the innner process(es) the outer process
+// reads the control files and does the merge based entirely on the contents
+// of control file.
+// It uses a single pass greedy algorithm choosing first the smallest inputs
+// within the same size the inputs that have more new features.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_MERGE_H
+#define LLVM_FUZZER_MERGE_H
+
+#include "FuzzerDefs.h"
+
+#include <istream>
+#include <ostream>
+#include <set>
+#include <vector>
+
+namespace fuzzer {
+
+struct MergeFileInfo {
+ std::string Name;
+ size_t Size = 0;
+ Vector<uint32_t> Features;
+};
+
+struct Merger {
+ Vector<MergeFileInfo> Files;
+ size_t NumFilesInFirstCorpus = 0;
+ size_t FirstNotProcessedFile = 0;
+ std::string LastFailure;
+
+ bool Parse(std::istream &IS, bool ParseCoverage);
+ bool Parse(const std::string &Str, bool ParseCoverage);
+ void ParseOrExit(std::istream &IS, bool ParseCoverage);
+ void PrintSummary(std::ostream &OS);
+ Set<uint32_t> ParseSummary(std::istream &IS);
+ size_t Merge(const Set<uint32_t> &InitialFeatures,
+ Vector<std::string> *NewFiles);
+ size_t Merge(Vector<std::string> *NewFiles) {
+ return Merge(Set<uint32_t>{}, NewFiles);
+ }
+ size_t ApproximateMemoryConsumption() const;
+ Set<uint32_t> AllFeatures() const;
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_MERGE_H
diff --git a/lib/fuzzer/FuzzerMutate.cpp b/lib/fuzzer/FuzzerMutate.cpp
new file mode 100644
index 000000000000..9ee5299f1b60
--- /dev/null
+++ b/lib/fuzzer/FuzzerMutate.cpp
@@ -0,0 +1,533 @@
+//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Mutate a test input.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerMutate.h"
+#include "FuzzerCorpus.h"
+#include "FuzzerDefs.h"
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include "FuzzerOptions.h"
+
+namespace fuzzer {
+
+const size_t Dictionary::kMaxDictSize;
+
+static void PrintASCII(const Word &W, const char *PrintAfter) {
+ PrintASCII(W.data(), W.size(), PrintAfter);
+}
+
+MutationDispatcher::MutationDispatcher(Random &Rand,
+ const FuzzingOptions &Options)
+ : Rand(Rand), Options(Options) {
+ DefaultMutators.insert(
+ DefaultMutators.begin(),
+ {
+ {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
+ {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
+ {&MutationDispatcher::Mutate_InsertRepeatedBytes,
+ "InsertRepeatedBytes"},
+ {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
+ {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
+ {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
+ {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
+ {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
+ {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
+ {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
+ {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
+ "ManualDict"},
+ {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
+ "PersAutoDict"},
+ });
+ if(Options.UseCmp)
+ DefaultMutators.push_back(
+ {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
+
+ if (EF->LLVMFuzzerCustomMutator)
+ Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
+ else
+ Mutators = DefaultMutators;
+
+ if (EF->LLVMFuzzerCustomCrossOver)
+ Mutators.push_back(
+ {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
+}
+
+static char RandCh(Random &Rand) {
+ if (Rand.RandBool()) return Rand(256);
+ const char *Special = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
+ return Special[Rand(sizeof(Special) - 1)];
+}
+
+size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand());
+}
+
+size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (!Corpus || Corpus->size() < 2 || Size == 0)
+ return 0;
+ size_t Idx = Rand(Corpus->size());
+ const Unit &Other = (*Corpus)[Idx];
+ if (Other.empty())
+ return 0;
+ CustomCrossOverInPlaceHere.resize(MaxSize);
+ auto &U = CustomCrossOverInPlaceHere;
+ size_t NewSize = EF->LLVMFuzzerCustomCrossOver(
+ Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand());
+ if (!NewSize)
+ return 0;
+ assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
+ memcpy(Data, U.data(), NewSize);
+ return NewSize;
+}
+
+size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize || Size == 0) return 0;
+ size_t ShuffleAmount =
+ Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
+ size_t ShuffleStart = Rand(Size - ShuffleAmount);
+ assert(ShuffleStart + ShuffleAmount <= Size);
+ std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size <= 1) return 0;
+ size_t N = Rand(Size / 2) + 1;
+ assert(N < Size);
+ size_t Idx = Rand(Size - N + 1);
+ // Erase Data[Idx:Idx+N].
+ memmove(Data + Idx, Data + Idx + N, Size - Idx - N);
+ // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);
+ return Size - N;
+}
+
+size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size >= MaxSize) return 0;
+ size_t Idx = Rand(Size + 1);
+ // Insert new value at Data[Idx].
+ memmove(Data + Idx + 1, Data + Idx, Size - Idx);
+ Data[Idx] = RandCh(Rand);
+ return Size + 1;
+}
+
+size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ const size_t kMinBytesToInsert = 3;
+ if (Size + kMinBytesToInsert >= MaxSize) return 0;
+ size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);
+ size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;
+ assert(Size + N <= MaxSize && N);
+ size_t Idx = Rand(Size + 1);
+ // Insert new values at Data[Idx].
+ memmove(Data + Idx + N, Data + Idx, Size - Idx);
+ // Give preference to 0x00 and 0xff.
+ uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255);
+ for (size_t i = 0; i < N; i++)
+ Data[Idx + i] = Byte;
+ return Size + N;
+}
+
+size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ size_t Idx = Rand(Size);
+ Data[Idx] = RandCh(Rand);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ size_t Idx = Rand(Size);
+ Data[Idx] ^= 1 << Rand(8);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
+ size_t MaxSize,
+ DictionaryEntry &DE) {
+ const Word &W = DE.GetW();
+ bool UsePositionHint = DE.HasPositionHint() &&
+ DE.GetPositionHint() + W.size() < Size &&
+ Rand.RandBool();
+ if (Rand.RandBool()) { // Insert W.
+ if (Size + W.size() > MaxSize) return 0;
+ size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
+ memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
+ memcpy(Data + Idx, W.data(), W.size());
+ Size += W.size();
+ } else { // Overwrite some bytes with W.
+ if (W.size() > Size) return 0;
+ size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
+ memcpy(Data + Idx, W.data(), W.size());
+ }
+ return Size;
+}
+
+// Somewhere in the past we have observed a comparison instructions
+// with arguments Arg1 Arg2. This function tries to guess a dictionary
+// entry that will satisfy that comparison.
+// It first tries to find one of the arguments (possibly swapped) in the
+// input and if it succeeds it creates a DE with a position hint.
+// Otherwise it creates a DE with one of the arguments w/o a position hint.
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+ const void *Arg1, const void *Arg2,
+ const void *Arg1Mutation, const void *Arg2Mutation,
+ size_t ArgSize, const uint8_t *Data,
+ size_t Size) {
+ ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str;
+ bool HandleFirst = Rand.RandBool();
+ const void *ExistingBytes, *DesiredBytes;
+ Word W;
+ const uint8_t *End = Data + Size;
+ for (int Arg = 0; Arg < 2; Arg++) {
+ ExistingBytes = HandleFirst ? Arg1 : Arg2;
+ DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation;
+ HandleFirst = !HandleFirst;
+ W.Set(reinterpret_cast<const uint8_t*>(DesiredBytes), ArgSize);
+ const size_t kMaxNumPositions = 8;
+ size_t Positions[kMaxNumPositions];
+ size_t NumPositions = 0;
+ for (const uint8_t *Cur = Data;
+ Cur < End && NumPositions < kMaxNumPositions; Cur++) {
+ Cur =
+ (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize);
+ if (!Cur) break;
+ Positions[NumPositions++] = Cur - Data;
+ }
+ if (!NumPositions) continue;
+ return DictionaryEntry(W, Positions[Rand(NumPositions)]);
+ }
+ DictionaryEntry DE(W);
+ return DE;
+}
+
+
+template <class T>
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+ T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
+ if (Rand.RandBool()) Arg1 = Bswap(Arg1);
+ if (Rand.RandBool()) Arg2 = Bswap(Arg2);
+ T Arg1Mutation = Arg1 + Rand(-1, 1);
+ T Arg2Mutation = Arg2 + Rand(-1, 1);
+ return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation,
+ sizeof(Arg1), Data, Size);
+}
+
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+ const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) {
+ return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(),
+ Arg2.data(), Arg1.size(), Data, Size);
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromTORC(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ Word W;
+ DictionaryEntry DE;
+ switch (Rand(4)) {
+ case 0: {
+ auto X = TPC.TORC8.Get(Rand.Rand());
+ DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+ } break;
+ case 1: {
+ auto X = TPC.TORC4.Get(Rand.Rand());
+ if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
+ DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size);
+ else
+ DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+ } break;
+ case 2: {
+ auto X = TPC.TORCW.Get(Rand.Rand());
+ DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+ } break;
+ case 3: if (Options.UseMemmem) {
+ auto X = TPC.MMT.Get(Rand.Rand());
+ DE = DictionaryEntry(X);
+ } break;
+ default:
+ assert(0);
+ }
+ if (!DE.GetW().size()) return 0;
+ Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
+ if (!Size) return 0;
+ DictionaryEntry &DERef =
+ CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
+ kCmpDictionaryEntriesDequeSize];
+ DERef = DE;
+ CurrentDictionaryEntrySequence.push_back(&DERef);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
+ size_t Size, size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ if (D.empty()) return 0;
+ DictionaryEntry &DE = D[Rand(D.size())];
+ Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
+ if (!Size) return 0;
+ DE.IncUseCount();
+ CurrentDictionaryEntrySequence.push_back(&DE);
+ return Size;
+}
+
+// Overwrites part of To[0,ToSize) with a part of From[0,FromSize).
+// Returns ToSize.
+size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize,
+ uint8_t *To, size_t ToSize) {
+ // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize).
+ size_t ToBeg = Rand(ToSize);
+ size_t CopySize = Rand(ToSize - ToBeg) + 1;
+ assert(ToBeg + CopySize <= ToSize);
+ CopySize = std::min(CopySize, FromSize);
+ size_t FromBeg = Rand(FromSize - CopySize + 1);
+ assert(FromBeg + CopySize <= FromSize);
+ memmove(To + ToBeg, From + FromBeg, CopySize);
+ return ToSize;
+}
+
+// Inserts part of From[0,ToSize) into To.
+// Returns new size of To on success or 0 on failure.
+size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,
+ uint8_t *To, size_t ToSize,
+ size_t MaxToSize) {
+ if (ToSize >= MaxToSize) return 0;
+ size_t AvailableSpace = MaxToSize - ToSize;
+ size_t MaxCopySize = std::min(AvailableSpace, FromSize);
+ size_t CopySize = Rand(MaxCopySize) + 1;
+ size_t FromBeg = Rand(FromSize - CopySize + 1);
+ assert(FromBeg + CopySize <= FromSize);
+ size_t ToInsertPos = Rand(ToSize + 1);
+ assert(ToInsertPos + CopySize <= MaxToSize);
+ size_t TailSize = ToSize - ToInsertPos;
+ if (To == From) {
+ MutateInPlaceHere.resize(MaxToSize);
+ memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize);
+ memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
+ memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize);
+ } else {
+ memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
+ memmove(To + ToInsertPos, From + FromBeg, CopySize);
+ }
+ return ToSize + CopySize;
+}
+
+size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize || Size == 0) return 0;
+ if (Rand.RandBool())
+ return CopyPartOf(Data, Size, Data, Size);
+ else
+ return InsertPartOf(Data, Size, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ size_t B = Rand(Size);
+ while (B < Size && !isdigit(Data[B])) B++;
+ if (B == Size) return 0;
+ size_t E = B;
+ while (E < Size && isdigit(Data[E])) E++;
+ assert(B < E);
+ // now we have digits in [B, E).
+ // strtol and friends don't accept non-zero-teminated data, parse it manually.
+ uint64_t Val = Data[B] - '0';
+ for (size_t i = B + 1; i < E; i++)
+ Val = Val * 10 + Data[i] - '0';
+
+ // Mutate the integer value.
+ switch(Rand(5)) {
+ case 0: Val++; break;
+ case 1: Val--; break;
+ case 2: Val /= 2; break;
+ case 3: Val *= 2; break;
+ case 4: Val = Rand(Val * Val); break;
+ default: assert(0);
+ }
+ // Just replace the bytes with the new ones, don't bother moving bytes.
+ for (size_t i = B; i < E; i++) {
+ size_t Idx = E + B - i - 1;
+ assert(Idx >= B && Idx < E);
+ Data[Idx] = (Val % 10) + '0';
+ Val /= 10;
+ }
+ return Size;
+}
+
+template<class T>
+size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
+ if (Size < sizeof(T)) return 0;
+ size_t Off = Rand(Size - sizeof(T) + 1);
+ assert(Off + sizeof(T) <= Size);
+ T Val;
+ if (Off < 64 && !Rand(4)) {
+ Val = Size;
+ if (Rand.RandBool())
+ Val = Bswap(Val);
+ } else {
+ memcpy(&Val, Data + Off, sizeof(Val));
+ T Add = Rand(21);
+ Add -= 10;
+ if (Rand.RandBool())
+ Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes.
+ else
+ Val = Val + Add; // Add assuming current endiannes.
+ if (Add == 0 || Rand.RandBool()) // Maybe negate.
+ Val = -Val;
+ }
+ memcpy(Data + Off, &Val, sizeof(Val));
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ switch (Rand(4)) {
+ case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand);
+ case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand);
+ case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand);
+ case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand);
+ default: assert(0);
+ }
+ return 0;
+}
+
+size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ if (!Corpus || Corpus->size() < 2 || Size == 0) return 0;
+ size_t Idx = Rand(Corpus->size());
+ const Unit &O = (*Corpus)[Idx];
+ if (O.empty()) return 0;
+ MutateInPlaceHere.resize(MaxSize);
+ auto &U = MutateInPlaceHere;
+ size_t NewSize = 0;
+ switch(Rand(3)) {
+ case 0:
+ NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size());
+ break;
+ case 1:
+ NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize);
+ if (!NewSize)
+ NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
+ break;
+ case 2:
+ NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
+ break;
+ default: assert(0);
+ }
+ assert(NewSize > 0 && "CrossOver returned empty unit");
+ assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
+ memcpy(Data, U.data(), NewSize);
+ return NewSize;
+}
+
+void MutationDispatcher::StartMutationSequence() {
+ CurrentMutatorSequence.clear();
+ CurrentDictionaryEntrySequence.clear();
+}
+
+// Copy successful dictionary entries to PersistentAutoDictionary.
+void MutationDispatcher::RecordSuccessfulMutationSequence() {
+ for (auto DE : CurrentDictionaryEntrySequence) {
+ // PersistentAutoDictionary.AddWithSuccessCountOne(DE);
+ DE->IncSuccessCount();
+ assert(DE->GetW().size());
+ // Linear search is fine here as this happens seldom.
+ if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
+ PersistentAutoDictionary.push_back({DE->GetW(), 1});
+ }
+}
+
+void MutationDispatcher::PrintRecommendedDictionary() {
+ Vector<DictionaryEntry> V;
+ for (auto &DE : PersistentAutoDictionary)
+ if (!ManualDictionary.ContainsWord(DE.GetW()))
+ V.push_back(DE);
+ if (V.empty()) return;
+ Printf("###### Recommended dictionary. ######\n");
+ for (auto &DE: V) {
+ assert(DE.GetW().size());
+ Printf("\"");
+ PrintASCII(DE.GetW(), "\"");
+ Printf(" # Uses: %zd\n", DE.GetUseCount());
+ }
+ Printf("###### End of recommended dictionary. ######\n");
+}
+
+void MutationDispatcher::PrintMutationSequence() {
+ Printf("MS: %zd ", CurrentMutatorSequence.size());
+ for (auto M : CurrentMutatorSequence)
+ Printf("%s-", M.Name);
+ if (!CurrentDictionaryEntrySequence.empty()) {
+ Printf(" DE: ");
+ for (auto DE : CurrentDictionaryEntrySequence) {
+ Printf("\"");
+ PrintASCII(DE->GetW(), "\"-");
+ }
+ }
+}
+
+size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+ return MutateImpl(Data, Size, MaxSize, Mutators);
+}
+
+size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ return MutateImpl(Data, Size, MaxSize, DefaultMutators);
+}
+
+// Mutates Data in place, returns new size.
+size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
+ size_t MaxSize,
+ Vector<Mutator> &Mutators) {
+ assert(MaxSize > 0);
+ // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
+ // in which case they will return 0.
+ // Try several times before returning un-mutated data.
+ for (int Iter = 0; Iter < 100; Iter++) {
+ auto M = Mutators[Rand(Mutators.size())];
+ size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
+ if (NewSize && NewSize <= MaxSize) {
+ if (Options.OnlyASCII)
+ ToASCII(Data, NewSize);
+ CurrentMutatorSequence.push_back(M);
+ return NewSize;
+ }
+ }
+ *Data = ' ';
+ return 1; // Fallback, should not happen frequently.
+}
+
+void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
+ ManualDictionary.push_back(
+ {W, std::numeric_limits<size_t>::max()});
+}
+
+} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerMutate.h b/lib/fuzzer/FuzzerMutate.h
new file mode 100644
index 000000000000..4aa58af9902d
--- /dev/null
+++ b/lib/fuzzer/FuzzerMutate.h
@@ -0,0 +1,150 @@
+//===- FuzzerMutate.h - Internal header for the Fuzzer ----------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::MutationDispatcher
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_MUTATE_H
+#define LLVM_FUZZER_MUTATE_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
+#include "FuzzerOptions.h"
+#include "FuzzerRandom.h"
+
+namespace fuzzer {
+
+class MutationDispatcher {
+public:
+ MutationDispatcher(Random &Rand, const FuzzingOptions &Options);
+ ~MutationDispatcher() {}
+ /// Indicate that we are about to start a new sequence of mutations.
+ void StartMutationSequence();
+ /// Print the current sequence of mutations.
+ void PrintMutationSequence();
+ /// Indicate that the current sequence of mutations was successfull.
+ void RecordSuccessfulMutationSequence();
+ /// Mutates data by invoking user-provided mutator.
+ size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by invoking user-provided crossover.
+ size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by shuffling bytes.
+ size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by erasing bytes.
+ size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by inserting a byte.
+ size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by inserting several repeated bytes.
+ size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by chanding one byte.
+ size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by chanding one bit.
+ size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by copying/inserting a part of data into a different place.
+ size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Mutates data by adding a word from the manual dictionary.
+ size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
+ /// Mutates data by adding a word from the TORC.
+ size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Mutates data by adding a word from the persistent automatic dictionary.
+ size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
+ /// Tries to find an ASCII integer in Data, changes it to another ASCII int.
+ size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways.
+ size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// CrossOver Data with some other element of the corpus.
+ size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Applies one of the configured mutations.
+ /// Returns the new size of data which could be up to MaxSize.
+ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Applies one of the default mutations. Provided as a service
+ /// to mutation authors.
+ size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Creates a cross-over of two pieces of Data, returns its size.
+ size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
+ size_t Size2, uint8_t *Out, size_t MaxOutSize);
+
+ void AddWordToManualDictionary(const Word &W);
+
+ void PrintRecommendedDictionary();
+
+ void SetCorpus(const InputCorpus *Corpus) { this->Corpus = Corpus; }
+
+ Random &GetRand() { return Rand; }
+
+private:
+
+ struct Mutator {
+ size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
+ const char *Name;
+ };
+
+ size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
+ size_t MaxSize);
+ size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
+ Vector<Mutator> &Mutators);
+
+ size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
+ size_t ToSize, size_t MaxToSize);
+ size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
+ size_t ToSize);
+ size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize,
+ DictionaryEntry &DE);
+
+ template <class T>
+ DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2,
+ const uint8_t *Data, size_t Size);
+ DictionaryEntry MakeDictionaryEntryFromCMP(const Word &Arg1, const Word &Arg2,
+ const uint8_t *Data, size_t Size);
+ DictionaryEntry MakeDictionaryEntryFromCMP(const void *Arg1, const void *Arg2,
+ const void *Arg1Mutation,
+ const void *Arg2Mutation,
+ size_t ArgSize,
+ const uint8_t *Data, size_t Size);
+
+ Random &Rand;
+ const FuzzingOptions Options;
+
+ // Dictionary provided by the user via -dict=DICT_FILE.
+ Dictionary ManualDictionary;
+ // Temporary dictionary modified by the fuzzer itself,
+ // recreated periodically.
+ Dictionary TempAutoDictionary;
+ // Persistent dictionary modified by the fuzzer, consists of
+ // entries that led to successfull discoveries in the past mutations.
+ Dictionary PersistentAutoDictionary;
+
+ Vector<Mutator> CurrentMutatorSequence;
+ Vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
+
+ static const size_t kCmpDictionaryEntriesDequeSize = 16;
+ DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
+ size_t CmpDictionaryEntriesDequeIdx = 0;
+
+ const InputCorpus *Corpus = nullptr;
+ Vector<uint8_t> MutateInPlaceHere;
+ // CustomCrossOver needs its own buffer as a custom implementation may call
+ // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere.
+ Vector<uint8_t> CustomCrossOverInPlaceHere;
+
+ Vector<Mutator> Mutators;
+ Vector<Mutator> DefaultMutators;
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_MUTATE_H
diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h
new file mode 100644
index 000000000000..15a378020b85
--- /dev/null
+++ b/lib/fuzzer/FuzzerOptions.h
@@ -0,0 +1,75 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::FuzzingOptions
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_OPTIONS_H
+#define LLVM_FUZZER_OPTIONS_H
+
+#include "FuzzerDefs.h"
+
+namespace fuzzer {
+
+struct FuzzingOptions {
+ int Verbosity = 1;
+ size_t MaxLen = 0;
+ size_t ExperimentalLenControl = 0;
+ int UnitTimeoutSec = 300;
+ int TimeoutExitCode = 77;
+ int ErrorExitCode = 77;
+ int MaxTotalTimeSec = 0;
+ int RssLimitMb = 0;
+ int MallocLimitMb = 0;
+ bool DoCrossOver = true;
+ int MutateDepth = 5;
+ bool ReduceDepth = false;
+ bool UseCounters = false;
+ bool UseMemmem = true;
+ bool UseCmp = false;
+ bool UseValueProfile = false;
+ bool Shrink = false;
+ bool ReduceInputs = false;
+ int ReloadIntervalSec = 1;
+ bool ShuffleAtStartUp = true;
+ bool PreferSmall = true;
+ size_t MaxNumberOfRuns = -1L;
+ int ReportSlowUnits = 10;
+ bool OnlyASCII = false;
+ std::string OutputCorpus;
+ std::string ArtifactPrefix = "./";
+ std::string ExactArtifactPath;
+ std::string ExitOnSrcPos;
+ std::string ExitOnItem;
+ bool SaveArtifacts = true;
+ bool PrintNEW = true; // Print a status line when new units are found;
+ bool PrintNewCovPcs = false;
+ int PrintNewCovFuncs = 0;
+ bool PrintFinalStats = false;
+ bool PrintCorpusStats = false;
+ bool PrintCoverage = false;
+ bool DumpCoverage = false;
+ bool UseClangCoverage = false;
+ bool DetectLeaks = true;
+ int PurgeAllocatorIntervalSec = 1;
+ int UseFeatureFrequency = false;
+ int TraceMalloc = 0;
+ bool HandleAbrt = false;
+ bool HandleBus = false;
+ bool HandleFpe = false;
+ bool HandleIll = false;
+ bool HandleInt = false;
+ bool HandleSegv = false;
+ bool HandleTerm = false;
+ bool HandleXfsz = false;
+ bool HandleUsr1 = false;
+ bool HandleUsr2 = false;
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_OPTIONS_H
diff --git a/lib/fuzzer/FuzzerRandom.h b/lib/fuzzer/FuzzerRandom.h
new file mode 100644
index 000000000000..8a1aa3ef5fdc
--- /dev/null
+++ b/lib/fuzzer/FuzzerRandom.h
@@ -0,0 +1,34 @@
+//===- FuzzerRandom.h - Internal header for the Fuzzer ----------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::Random
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_RANDOM_H
+#define LLVM_FUZZER_RANDOM_H
+
+#include <random>
+
+namespace fuzzer {
+class Random : public std::mt19937 {
+ public:
+ Random(unsigned int seed) : std::mt19937(seed) {}
+ result_type operator()() { return this->std::mt19937::operator()(); }
+ size_t Rand() { return this->operator()(); }
+ size_t RandBool() { return Rand() % 2; }
+ size_t operator()(size_t n) { return n ? Rand() % n : 0; }
+ intptr_t operator()(intptr_t From, intptr_t To) {
+ assert(From < To);
+ intptr_t RangeSize = To - From + 1;
+ return operator()(RangeSize) + From;
+ }
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_RANDOM_H
diff --git a/lib/fuzzer/FuzzerSHA1.cpp b/lib/fuzzer/FuzzerSHA1.cpp
new file mode 100644
index 000000000000..d2f8e811bbf8
--- /dev/null
+++ b/lib/fuzzer/FuzzerSHA1.cpp
@@ -0,0 +1,222 @@
+//===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This code is taken from public domain
+// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c)
+// and modified by adding anonymous namespace, adding an interface
+// function fuzzer::ComputeSHA1() and removing unnecessary code.
+//
+// lib/Fuzzer can not use SHA1 implementation from openssl because
+// openssl may not be available and because we may be fuzzing openssl itself.
+// For the same reason we do not want to depend on SHA1 from LLVM tree.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerSHA1.h"
+#include "FuzzerDefs.h"
+
+/* This code is public-domain - it is based on libcrypt
+ * placed in the public domain by Wei Dai and other contributors.
+ */
+
+#include <iomanip>
+#include <sstream>
+#include <stdint.h>
+#include <string.h>
+
+namespace { // Added for LibFuzzer
+
+#ifdef __BIG_ENDIAN__
+# define SHA_BIG_ENDIAN
+#elif defined __LITTLE_ENDIAN__
+/* override */
+#elif defined __BYTE_ORDER
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define SHA_BIG_ENDIAN
+# endif
+#else // ! defined __LITTLE_ENDIAN__
+# include <endian.h> // machine/endian.h
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define SHA_BIG_ENDIAN
+# endif
+#endif
+
+
+/* header */
+
+#define HASH_LENGTH 20
+#define BLOCK_LENGTH 64
+
+typedef struct sha1nfo {
+ uint32_t buffer[BLOCK_LENGTH/4];
+ uint32_t state[HASH_LENGTH/4];
+ uint32_t byteCount;
+ uint8_t bufferOffset;
+ uint8_t keyBuffer[BLOCK_LENGTH];
+ uint8_t innerHash[HASH_LENGTH];
+} sha1nfo;
+
+/* public API - prototypes - TODO: doxygen*/
+
+/**
+ */
+void sha1_init(sha1nfo *s);
+/**
+ */
+void sha1_writebyte(sha1nfo *s, uint8_t data);
+/**
+ */
+void sha1_write(sha1nfo *s, const char *data, size_t len);
+/**
+ */
+uint8_t* sha1_result(sha1nfo *s);
+
+
+/* code */
+#define SHA1_K0 0x5a827999
+#define SHA1_K20 0x6ed9eba1
+#define SHA1_K40 0x8f1bbcdc
+#define SHA1_K60 0xca62c1d6
+
+void sha1_init(sha1nfo *s) {
+ s->state[0] = 0x67452301;
+ s->state[1] = 0xefcdab89;
+ s->state[2] = 0x98badcfe;
+ s->state[3] = 0x10325476;
+ s->state[4] = 0xc3d2e1f0;
+ s->byteCount = 0;
+ s->bufferOffset = 0;
+}
+
+uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
+ return ((number << bits) | (number >> (32-bits)));
+}
+
+void sha1_hashBlock(sha1nfo *s) {
+ uint8_t i;
+ uint32_t a,b,c,d,e,t;
+
+ a=s->state[0];
+ b=s->state[1];
+ c=s->state[2];
+ d=s->state[3];
+ e=s->state[4];
+ for (i=0; i<80; i++) {
+ if (i>=16) {
+ t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15];
+ s->buffer[i&15] = sha1_rol32(t,1);
+ }
+ if (i<20) {
+ t = (d ^ (b & (c ^ d))) + SHA1_K0;
+ } else if (i<40) {
+ t = (b ^ c ^ d) + SHA1_K20;
+ } else if (i<60) {
+ t = ((b & c) | (d & (b | c))) + SHA1_K40;
+ } else {
+ t = (b ^ c ^ d) + SHA1_K60;
+ }
+ t+=sha1_rol32(a,5) + e + s->buffer[i&15];
+ e=d;
+ d=c;
+ c=sha1_rol32(b,30);
+ b=a;
+ a=t;
+ }
+ s->state[0] += a;
+ s->state[1] += b;
+ s->state[2] += c;
+ s->state[3] += d;
+ s->state[4] += e;
+}
+
+void sha1_addUncounted(sha1nfo *s, uint8_t data) {
+ uint8_t * const b = (uint8_t*) s->buffer;
+#ifdef SHA_BIG_ENDIAN
+ b[s->bufferOffset] = data;
+#else
+ b[s->bufferOffset ^ 3] = data;
+#endif
+ s->bufferOffset++;
+ if (s->bufferOffset == BLOCK_LENGTH) {
+ sha1_hashBlock(s);
+ s->bufferOffset = 0;
+ }
+}
+
+void sha1_writebyte(sha1nfo *s, uint8_t data) {
+ ++s->byteCount;
+ sha1_addUncounted(s, data);
+}
+
+void sha1_write(sha1nfo *s, const char *data, size_t len) {
+ for (;len--;) sha1_writebyte(s, (uint8_t) *data++);
+}
+
+void sha1_pad(sha1nfo *s) {
+ // Implement SHA-1 padding (fips180-2 ยง5.1.1)
+
+ // Pad with 0x80 followed by 0x00 until the end of the block
+ sha1_addUncounted(s, 0x80);
+ while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
+
+ // Append length in the last 8 bytes
+ sha1_addUncounted(s, 0); // We're only using 32 bit lengths
+ sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
+ sha1_addUncounted(s, 0); // So zero pad the top bits
+ sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
+ sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
+ sha1_addUncounted(s, s->byteCount >> 13); // byte.
+ sha1_addUncounted(s, s->byteCount >> 5);
+ sha1_addUncounted(s, s->byteCount << 3);
+}
+
+uint8_t* sha1_result(sha1nfo *s) {
+ // Pad to complete the last block
+ sha1_pad(s);
+
+#ifndef SHA_BIG_ENDIAN
+ // Swap byte order back
+ int i;
+ for (i=0; i<5; i++) {
+ s->state[i]=
+ (((s->state[i])<<24)& 0xff000000)
+ | (((s->state[i])<<8) & 0x00ff0000)
+ | (((s->state[i])>>8) & 0x0000ff00)
+ | (((s->state[i])>>24)& 0x000000ff);
+ }
+#endif
+
+ // Return pointer to hash (20 characters)
+ return (uint8_t*) s->state;
+}
+
+} // namespace; Added for LibFuzzer
+
+namespace fuzzer {
+
+// The rest is added for LibFuzzer
+void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) {
+ sha1nfo s;
+ sha1_init(&s);
+ sha1_write(&s, (const char*)Data, Len);
+ memcpy(Out, sha1_result(&s), HASH_LENGTH);
+}
+
+std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) {
+ std::stringstream SS;
+ for (int i = 0; i < kSHA1NumBytes; i++)
+ SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i];
+ return SS.str();
+}
+
+std::string Hash(const Unit &U) {
+ uint8_t Hash[kSHA1NumBytes];
+ ComputeSHA1(U.data(), U.size(), Hash);
+ return Sha1ToString(Hash);
+}
+
+}
diff --git a/lib/fuzzer/FuzzerSHA1.h b/lib/fuzzer/FuzzerSHA1.h
new file mode 100644
index 000000000000..3b5e6e807f42
--- /dev/null
+++ b/lib/fuzzer/FuzzerSHA1.h
@@ -0,0 +1,33 @@
+//===- FuzzerSHA1.h - Internal header for the SHA1 utils --------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// SHA1 utils.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_SHA1_H
+#define LLVM_FUZZER_SHA1_H
+
+#include "FuzzerDefs.h"
+#include <cstddef>
+#include <stdint.h>
+
+namespace fuzzer {
+
+// Private copy of SHA1 implementation.
+static const int kSHA1NumBytes = 20;
+
+// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'.
+void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out);
+
+std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]);
+
+std::string Hash(const Unit &U);
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_SHA1_H
diff --git a/lib/fuzzer/FuzzerShmem.h b/lib/fuzzer/FuzzerShmem.h
new file mode 100644
index 000000000000..53568e0acb69
--- /dev/null
+++ b/lib/fuzzer/FuzzerShmem.h
@@ -0,0 +1,69 @@
+//===- FuzzerShmem.h - shared memory interface ------------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// SharedMemoryRegion
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_SHMEM_H
+#define LLVM_FUZZER_SHMEM_H
+
+#include <algorithm>
+#include <cstring>
+#include <string>
+
+#include "FuzzerDefs.h"
+
+namespace fuzzer {
+
+class SharedMemoryRegion {
+ public:
+ bool Create(const char *Name);
+ bool Open(const char *Name);
+ bool Destroy(const char *Name);
+ uint8_t *GetData() { return Data; }
+ void PostServer() {Post(0);}
+ void WaitServer() {Wait(0);}
+ void PostClient() {Post(1);}
+ void WaitClient() {Wait(1);}
+
+ size_t WriteByteArray(const uint8_t *Bytes, size_t N) {
+ assert(N <= kShmemSize - sizeof(N));
+ memcpy(GetData(), &N, sizeof(N));
+ memcpy(GetData() + sizeof(N), Bytes, N);
+ assert(N == ReadByteArraySize());
+ return N;
+ }
+ size_t ReadByteArraySize() {
+ size_t Res;
+ memcpy(&Res, GetData(), sizeof(Res));
+ return Res;
+ }
+ uint8_t *GetByteArray() { return GetData() + sizeof(size_t); }
+
+ bool IsServer() const { return Data && IAmServer; }
+ bool IsClient() const { return Data && !IAmServer; }
+
+private:
+
+ static const size_t kShmemSize = 1 << 22;
+ bool IAmServer;
+ std::string Path(const char *Name);
+ std::string SemName(const char *Name, int Idx);
+ void Post(int Idx);
+ void Wait(int Idx);
+
+ bool Map(int fd);
+ uint8_t *Data = nullptr;
+ void *Semaphore[2];
+};
+
+extern SharedMemoryRegion SMR;
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_SHMEM_H
diff --git a/lib/fuzzer/FuzzerShmemFuchsia.cpp b/lib/fuzzer/FuzzerShmemFuchsia.cpp
new file mode 100644
index 000000000000..e9ce50c2ac8a
--- /dev/null
+++ b/lib/fuzzer/FuzzerShmemFuchsia.cpp
@@ -0,0 +1,38 @@
+//===- FuzzerShmemPosix.cpp - Posix shared memory ---------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// SharedMemoryRegion. For Fuchsia, this is just stubs as equivalence servers
+// are not currently supported.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_FUCHSIA
+
+#include "FuzzerShmem.h"
+
+namespace fuzzer {
+
+bool SharedMemoryRegion::Create(const char *Name) {
+ return false;
+}
+
+bool SharedMemoryRegion::Open(const char *Name) {
+ return false;
+}
+
+bool SharedMemoryRegion::Destroy(const char *Name) {
+ return false;
+}
+
+void SharedMemoryRegion::Post(int Idx) {}
+
+void SharedMemoryRegion::Wait(int Idx) {}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_FUCHSIA
diff --git a/lib/fuzzer/FuzzerShmemPosix.cpp b/lib/fuzzer/FuzzerShmemPosix.cpp
new file mode 100644
index 000000000000..50cdcfb509dc
--- /dev/null
+++ b/lib/fuzzer/FuzzerShmemPosix.cpp
@@ -0,0 +1,103 @@
+//===- FuzzerShmemPosix.cpp - Posix shared memory ---------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// SharedMemoryRegion
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_POSIX
+
+#include "FuzzerIO.h"
+#include "FuzzerShmem.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace fuzzer {
+
+std::string SharedMemoryRegion::Path(const char *Name) {
+ return DirPlusFile(TmpDir(), Name);
+}
+
+std::string SharedMemoryRegion::SemName(const char *Name, int Idx) {
+ std::string Res(Name);
+ return Res + (char)('0' + Idx);
+}
+
+bool SharedMemoryRegion::Map(int fd) {
+ Data =
+ (uint8_t *)mmap(0, kShmemSize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
+ if (Data == (uint8_t*)-1)
+ return false;
+ return true;
+}
+
+bool SharedMemoryRegion::Create(const char *Name) {
+ int fd = open(Path(Name).c_str(), O_CREAT | O_RDWR, 0777);
+ if (fd < 0) return false;
+ if (ftruncate(fd, kShmemSize) < 0) return false;
+ if (!Map(fd))
+ return false;
+ for (int i = 0; i < 2; i++) {
+ sem_unlink(SemName(Name, i).c_str());
+ Semaphore[i] = sem_open(SemName(Name, i).c_str(), O_CREAT, 0644, 0);
+ if (Semaphore[i] == (void *)-1)
+ return false;
+ }
+ IAmServer = true;
+ return true;
+}
+
+bool SharedMemoryRegion::Open(const char *Name) {
+ int fd = open(Path(Name).c_str(), O_RDWR);
+ if (fd < 0) return false;
+ struct stat stat_res;
+ if (0 != fstat(fd, &stat_res))
+ return false;
+ assert(stat_res.st_size == kShmemSize);
+ if (!Map(fd))
+ return false;
+ for (int i = 0; i < 2; i++) {
+ Semaphore[i] = sem_open(SemName(Name, i).c_str(), 0);
+ if (Semaphore[i] == (void *)-1)
+ return false;
+ }
+ IAmServer = false;
+ return true;
+}
+
+bool SharedMemoryRegion::Destroy(const char *Name) {
+ return 0 == unlink(Path(Name).c_str());
+}
+
+void SharedMemoryRegion::Post(int Idx) {
+ assert(Idx == 0 || Idx == 1);
+ sem_post((sem_t*)Semaphore[Idx]);
+}
+
+void SharedMemoryRegion::Wait(int Idx) {
+ assert(Idx == 0 || Idx == 1);
+ for (int i = 0; i < 10 && sem_wait((sem_t*)Semaphore[Idx]); i++) {
+ // sem_wait may fail if interrupted by a signal.
+ sleep(i);
+ if (i)
+ Printf("%s: sem_wait[%d] failed %s\n", i < 9 ? "WARNING" : "ERROR", i,
+ strerror(errno));
+ if (i == 9) abort();
+ }
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_POSIX
diff --git a/lib/fuzzer/FuzzerShmemWindows.cpp b/lib/fuzzer/FuzzerShmemWindows.cpp
new file mode 100644
index 000000000000..d330ebf4fd07
--- /dev/null
+++ b/lib/fuzzer/FuzzerShmemWindows.cpp
@@ -0,0 +1,64 @@
+//===- FuzzerShmemWindows.cpp - Posix shared memory -------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// SharedMemoryRegion
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_WINDOWS
+
+#include "FuzzerIO.h"
+#include "FuzzerShmem.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace fuzzer {
+
+std::string SharedMemoryRegion::Path(const char *Name) {
+ return DirPlusFile(TmpDir(), Name);
+}
+
+std::string SharedMemoryRegion::SemName(const char *Name, int Idx) {
+ std::string Res(Name);
+ return Res + (char)('0' + Idx);
+}
+
+bool SharedMemoryRegion::Map(int fd) {
+ assert(0 && "UNIMPLEMENTED");
+ return false;
+}
+
+bool SharedMemoryRegion::Create(const char *Name) {
+ assert(0 && "UNIMPLEMENTED");
+ return false;
+}
+
+bool SharedMemoryRegion::Open(const char *Name) {
+ assert(0 && "UNIMPLEMENTED");
+ return false;
+}
+
+bool SharedMemoryRegion::Destroy(const char *Name) {
+ assert(0 && "UNIMPLEMENTED");
+ return false;
+}
+
+void SharedMemoryRegion::Post(int Idx) {
+ assert(0 && "UNIMPLEMENTED");
+}
+
+void SharedMemoryRegion::Wait(int Idx) {
+ Semaphore[1] = nullptr;
+ assert(0 && "UNIMPLEMENTED");
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_WINDOWS
diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp
new file mode 100644
index 000000000000..5e9f9f2f6dcc
--- /dev/null
+++ b/lib/fuzzer/FuzzerTracePC.cpp
@@ -0,0 +1,602 @@
+//===- FuzzerTracePC.cpp - PC tracing--------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Trace PCs.
+// This module implements __sanitizer_cov_trace_pc_guard[_init],
+// the callback required for -fsanitize-coverage=trace-pc-guard instrumentation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerTracePC.h"
+#include "FuzzerCorpus.h"
+#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include "FuzzerUtil.h"
+#include "FuzzerValueBitMap.h"
+#include <set>
+
+// The coverage counters and PCs.
+// These are declared as global variables named "__sancov_*" to simplify
+// experiments with inlined instrumentation.
+alignas(64) ATTRIBUTE_INTERFACE
+uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs];
+
+ATTRIBUTE_INTERFACE
+uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
+
+// Used by -fsanitize-coverage=stack-depth to track stack depth
+ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec")))
+thread_local uintptr_t __sancov_lowest_stack;
+
+namespace fuzzer {
+
+TracePC TPC;
+
+int ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr;
+
+uint8_t *TracePC::Counters() const {
+ return __sancov_trace_pc_guard_8bit_counters;
+}
+
+uintptr_t *TracePC::PCs() const {
+ return __sancov_trace_pc_pcs;
+}
+
+size_t TracePC::GetTotalPCCoverage() {
+ if (ObservedPCs.size())
+ return ObservedPCs.size();
+ size_t Res = 0;
+ for (size_t i = 1, N = GetNumPCs(); i < N; i++)
+ if (PCs()[i])
+ Res++;
+ return Res;
+}
+
+
+void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
+ if (Start == Stop) return;
+ if (NumModulesWithInline8bitCounters &&
+ ModuleCounters[NumModulesWithInline8bitCounters-1].Start == Start) return;
+ assert(NumModulesWithInline8bitCounters <
+ sizeof(ModuleCounters) / sizeof(ModuleCounters[0]));
+ ModuleCounters[NumModulesWithInline8bitCounters++] = {Start, Stop};
+ NumInline8bitCounters += Stop - Start;
+}
+
+void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
+ const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
+ const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
+ if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return;
+ assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0]));
+ ModulePCTable[NumPCTables++] = {B, E};
+ NumPCsInPCTables += E - B;
+}
+
+void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) {
+ if (Start == Stop || *Start) return;
+ assert(NumModules < sizeof(Modules) / sizeof(Modules[0]));
+ for (uint32_t *P = Start; P < Stop; P++) {
+ NumGuards++;
+ if (NumGuards == kNumPCs) {
+ RawPrint(
+ "WARNING: The binary has too many instrumented PCs.\n"
+ " You may want to reduce the size of the binary\n"
+ " for more efficient fuzzing and precise coverage data\n");
+ }
+ *P = NumGuards % kNumPCs;
+ }
+ Modules[NumModules].Start = Start;
+ Modules[NumModules].Stop = Stop;
+ NumModules++;
+}
+
+void TracePC::PrintModuleInfo() {
+ if (NumGuards) {
+ Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards);
+ for (size_t i = 0; i < NumModules; i++)
+ Printf("%zd [%p, %p), ", Modules[i].Stop - Modules[i].Start,
+ Modules[i].Start, Modules[i].Stop);
+ Printf("\n");
+ }
+ if (NumModulesWithInline8bitCounters) {
+ Printf("INFO: Loaded %zd modules (%zd inline 8-bit counters): ",
+ NumModulesWithInline8bitCounters, NumInline8bitCounters);
+ for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++)
+ Printf("%zd [%p, %p), ", ModuleCounters[i].Stop - ModuleCounters[i].Start,
+ ModuleCounters[i].Start, ModuleCounters[i].Stop);
+ Printf("\n");
+ }
+ if (NumPCTables) {
+ Printf("INFO: Loaded %zd PC tables (%zd PCs): ", NumPCTables,
+ NumPCsInPCTables);
+ for (size_t i = 0; i < NumPCTables; i++) {
+ Printf("%zd [%p,%p), ", ModulePCTable[i].Stop - ModulePCTable[i].Start,
+ ModulePCTable[i].Start, ModulePCTable[i].Stop);
+ }
+ Printf("\n");
+
+ if ((NumGuards && NumGuards != NumPCsInPCTables) ||
+ (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables)) {
+ Printf("ERROR: The size of coverage PC tables does not match the\n"
+ "number of instrumented PCs. This might be a compiler bug,\n"
+ "please contact the libFuzzer developers.\n"
+ "Also check https://bugs.llvm.org/show_bug.cgi?id=34636\n"
+ "for possible workarounds (tl;dr: don't use the old GNU ld)\n");
+ _Exit(1);
+ }
+ }
+ if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin())
+ Printf("INFO: %zd Clang Coverage Counters\n", NumClangCounters);
+}
+
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
+ const uintptr_t kBits = 12;
+ const uintptr_t kMask = (1 << kBits) - 1;
+ uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
+ ValueProfileMap.AddValueModPrime(Idx);
+}
+
+void TracePC::UpdateObservedPCs() {
+ Vector<uintptr_t> CoveredFuncs;
+ auto ObservePC = [&](uintptr_t PC) {
+ if (ObservedPCs.insert(PC).second && DoPrintNewPCs)
+ PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1);
+ };
+
+ auto Observe = [&](const PCTableEntry &TE) {
+ if (TE.PCFlags & 1)
+ if (ObservedFuncs.insert(TE.PC).second && NumPrintNewFuncs)
+ CoveredFuncs.push_back(TE.PC);
+ ObservePC(TE.PC);
+ };
+
+ if (NumPCsInPCTables) {
+ if (NumInline8bitCounters == NumPCsInPCTables) {
+ for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
+ uint8_t *Beg = ModuleCounters[i].Start;
+ size_t Size = ModuleCounters[i].Stop - Beg;
+ assert(Size ==
+ (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
+ for (size_t j = 0; j < Size; j++)
+ if (Beg[j])
+ Observe(ModulePCTable[i].Start[j]);
+ }
+ } else if (NumGuards == NumPCsInPCTables) {
+ size_t GuardIdx = 1;
+ for (size_t i = 0; i < NumModules; i++) {
+ uint32_t *Beg = Modules[i].Start;
+ size_t Size = Modules[i].Stop - Beg;
+ assert(Size ==
+ (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
+ for (size_t j = 0; j < Size; j++, GuardIdx++)
+ if (Counters()[GuardIdx])
+ Observe(ModulePCTable[i].Start[j]);
+ }
+ }
+ }
+ if (size_t NumClangCounters =
+ ClangCountersEnd() - ClangCountersBegin()) {
+ auto P = ClangCountersBegin();
+ for (size_t Idx = 0; Idx < NumClangCounters; Idx++)
+ if (P[Idx])
+ ObservePC((uintptr_t)Idx);
+ }
+
+ for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; i++) {
+ Printf("\tNEW_FUNC[%zd/%zd]: ", i, CoveredFuncs.size());
+ PrintPC("%p %F %L\n", "%p\n", CoveredFuncs[i] + 1);
+ }
+}
+
+inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
+ // TODO: this implementation is x86 only.
+ // see sanitizer_common GetPreviousInstructionPc for full implementation.
+ return PC - 1;
+}
+
+inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
+ // TODO: this implementation is x86 only.
+ // see sanitizer_common GetPreviousInstructionPc for full implementation.
+ return PC + 1;
+}
+
+static std::string GetModuleName(uintptr_t PC) {
+ char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
+ void *OffsetRaw = nullptr;
+ if (!EF->__sanitizer_get_module_and_offset_for_pc(
+ reinterpret_cast<void *>(PC), ModulePathRaw,
+ sizeof(ModulePathRaw), &OffsetRaw))
+ return "";
+ return ModulePathRaw;
+}
+
+void TracePC::PrintCoverage() {
+ if (!EF->__sanitizer_symbolize_pc ||
+ !EF->__sanitizer_get_module_and_offset_for_pc) {
+ Printf("INFO: __sanitizer_symbolize_pc or "
+ "__sanitizer_get_module_and_offset_for_pc is not available,"
+ " not printing coverage\n");
+ return;
+ }
+ Printf("COVERAGE:\n");
+ std::string LastFunctionName = "";
+ std::string LastFileStr = "";
+ Set<size_t> UncoveredLines;
+ Set<size_t> CoveredLines;
+
+ auto FunctionEndCallback = [&](const std::string &CurrentFunc,
+ const std::string &CurrentFile) {
+ if (LastFunctionName != CurrentFunc) {
+ if (CoveredLines.empty() && !UncoveredLines.empty()) {
+ Printf("UNCOVERED_FUNC: %s\n", LastFunctionName.c_str());
+ } else {
+ for (auto Line : UncoveredLines) {
+ if (!CoveredLines.count(Line))
+ Printf("UNCOVERED_LINE: %s %s:%zd\n", LastFunctionName.c_str(),
+ LastFileStr.c_str(), Line);
+ }
+ }
+
+ UncoveredLines.clear();
+ CoveredLines.clear();
+ LastFunctionName = CurrentFunc;
+ LastFileStr = CurrentFile;
+ }
+ };
+
+ for (size_t i = 0; i < NumPCTables; i++) {
+ auto &M = ModulePCTable[i];
+ assert(M.Start < M.Stop);
+ auto ModuleName = GetModuleName(M.Start->PC);
+ for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) {
+ auto PC = Ptr->PC;
+ auto VisualizePC = GetNextInstructionPc(PC);
+ bool IsObserved = ObservedPCs.count(PC);
+ std::string FileStr = DescribePC("%s", VisualizePC);
+ if (!IsInterestingCoverageFile(FileStr)) continue;
+ std::string FunctionStr = DescribePC("%F", VisualizePC);
+ FunctionEndCallback(FunctionStr, FileStr);
+ std::string LineStr = DescribePC("%l", VisualizePC);
+ size_t Line = std::stoul(LineStr);
+ if (IsObserved && CoveredLines.insert(Line).second)
+ Printf("COVERED: %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(),
+ Line);
+ else
+ UncoveredLines.insert(Line);
+ }
+ }
+ FunctionEndCallback("", "");
+}
+
+void TracePC::DumpCoverage() {
+ if (EF->__sanitizer_dump_coverage) {
+ Vector<uintptr_t> PCsCopy(GetNumPCs());
+ for (size_t i = 0; i < GetNumPCs(); i++)
+ PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0;
+ EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size());
+ }
+}
+
+// Value profile.
+// We keep track of various values that affect control flow.
+// These values are inserted into a bit-set-based hash map.
+// Every new bit in the map is treated as a new coverage.
+//
+// For memcmp/strcmp/etc the interesting value is the length of the common
+// prefix of the parameters.
+// For cmp instructions the interesting value is a XOR of the parameters.
+// The interesting value is mixed up with the PC and is then added to the map.
+
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
+ size_t n, bool StopAtZero) {
+ if (!n) return;
+ size_t Len = std::min(n, Word::GetMaxSize());
+ const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
+ const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
+ uint8_t B1[Word::kMaxSize];
+ uint8_t B2[Word::kMaxSize];
+ // Copy the data into locals in this non-msan-instrumented function
+ // to avoid msan complaining further.
+ size_t Hash = 0; // Compute some simple hash of both strings.
+ for (size_t i = 0; i < Len; i++) {
+ B1[i] = A1[i];
+ B2[i] = A2[i];
+ size_t T = B1[i];
+ Hash ^= (T << 8) | B2[i];
+ }
+ size_t I = 0;
+ for (; I < Len; I++)
+ if (B1[I] != B2[I] || (StopAtZero && B1[I] == 0))
+ break;
+ size_t PC = reinterpret_cast<size_t>(caller_pc);
+ size_t Idx = (PC & 4095) | (I << 12);
+ ValueProfileMap.AddValue(Idx);
+ TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len));
+}
+
+template <class T>
+ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
+ uint64_t ArgXor = Arg1 ^ Arg2;
+ uint64_t ArgDistance = __builtin_popcountll(ArgXor) + 1; // [1,65]
+ uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance;
+ if (sizeof(T) == 4)
+ TORC4.Insert(ArgXor, Arg1, Arg2);
+ else if (sizeof(T) == 8)
+ TORC8.Insert(ArgXor, Arg1, Arg2);
+ ValueProfileMap.AddValue(Idx);
+}
+
+static size_t InternalStrnlen(const char *S, size_t MaxLen) {
+ size_t Len = 0;
+ for (; Len < MaxLen && S[Len]; Len++) {}
+ return Len;
+}
+
+// Finds min of (strlen(S1), strlen(S2)).
+// Needed bacause one of these strings may actually be non-zero terminated.
+static size_t InternalStrnlen2(const char *S1, const char *S2) {
+ size_t Len = 0;
+ for (; S1[Len] && S2[Len]; Len++) {}
+ return Len;
+}
+
+void TracePC::ClearInlineCounters() {
+ for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
+ uint8_t *Beg = ModuleCounters[i].Start;
+ size_t Size = ModuleCounters[i].Stop - Beg;
+ memset(Beg, 0, Size);
+ }
+}
+
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::RecordInitialStack() {
+ int stack;
+ __sancov_lowest_stack = InitialStack = reinterpret_cast<uintptr_t>(&stack);
+}
+
+uintptr_t TracePC::GetMaxStackOffset() const {
+ return InitialStack - __sancov_lowest_stack; // Stack grows down
+}
+
+} // namespace fuzzer
+
+extern "C" {
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uint32_t Idx = *Guard;
+ __sancov_trace_pc_pcs[Idx] = PC;
+ __sancov_trace_pc_guard_8bit_counters[Idx]++;
+}
+
+// Best-effort support for -fsanitize-coverage=trace-pc, which is available
+// in both Clang and GCC.
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+void __sanitizer_cov_trace_pc() {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1);
+ __sancov_trace_pc_pcs[Idx] = PC;
+ __sancov_trace_pc_guard_8bit_counters[Idx]++;
+}
+
+ATTRIBUTE_INTERFACE
+void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
+ fuzzer::TPC.HandleInit(Start, Stop);
+}
+
+ATTRIBUTE_INTERFACE
+void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) {
+ fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop);
+}
+
+ATTRIBUTE_INTERFACE
+void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
+ const uintptr_t *pcs_end) {
+ fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCallerCallee(PC, Callee);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+// Now the __sanitizer_cov_trace_const_cmp[1248] callbacks just mimic
+// the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however,
+// should be changed later to make full use of instrumentation.
+void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
+ uint64_t N = Cases[0];
+ uint64_t ValSizeInBits = Cases[1];
+ uint64_t *Vals = Cases + 2;
+ // Skip the most common and the most boring case.
+ if (Vals[N - 1] < 256 && Val < 256)
+ return;
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ size_t i;
+ uint64_t Token = 0;
+ for (i = 0; i < N; i++) {
+ Token = Val ^ Vals[i];
+ if (Val < Vals[i])
+ break;
+ }
+
+ if (ValSizeInBits == 16)
+ fuzzer::TPC.HandleCmp(PC + i, static_cast<uint16_t>(Token), (uint16_t)(0));
+ else if (ValSizeInBits == 32)
+ fuzzer::TPC.HandleCmp(PC + i, static_cast<uint32_t>(Token), (uint32_t)(0));
+ else
+ fuzzer::TPC.HandleCmp(PC + i, Token, (uint64_t)(0));
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_div4(uint32_t Val) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_div8(uint64_t Val) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_gep(uintptr_t Idx) {
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
+ const void *s2, size_t n, int result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+ if (result == 0) return; // No reason to mutate.
+ if (n <= 1) return; // Not interesting.
+ fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
+ const char *s2, size_t n, int result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+ if (result == 0) return; // No reason to mutate.
+ size_t Len1 = fuzzer::InternalStrnlen(s1, n);
+ size_t Len2 = fuzzer::InternalStrnlen(s2, n);
+ n = std::min(n, Len1);
+ n = std::min(n, Len2);
+ if (n <= 1) return; // Not interesting.
+ fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
+ const char *s2, int result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+ if (result == 0) return; // No reason to mutate.
+ size_t N = fuzzer::InternalStrnlen2(s1, s2);
+ if (N <= 1) return; // Not interesting.
+ fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
+ const char *s2, size_t n, int result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+ return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
+ const char *s2, int result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+ return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
+ const char *s2, char *result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+ fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
+ const char *s2, char *result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+ fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
+ const void *s2, size_t len2, void *result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+ fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), len2);
+}
+} // extern "C"
diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h
new file mode 100644
index 000000000000..dc65cd72091a
--- /dev/null
+++ b/lib/fuzzer/FuzzerTracePC.h
@@ -0,0 +1,296 @@
+//===- FuzzerTracePC.h - Internal header for the Fuzzer ---------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::TracePC
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_TRACE_PC
+#define LLVM_FUZZER_TRACE_PC
+
+#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
+#include "FuzzerValueBitMap.h"
+
+#include <set>
+
+namespace fuzzer {
+
+// TableOfRecentCompares (TORC) remembers the most recently performed
+// comparisons of type T.
+// We record the arguments of CMP instructions in this table unconditionally
+// because it seems cheaper this way than to compute some expensive
+// conditions inside __sanitizer_cov_trace_cmp*.
+// After the unit has been executed we may decide to use the contents of
+// this table to populate a Dictionary.
+template<class T, size_t kSizeT>
+struct TableOfRecentCompares {
+ static const size_t kSize = kSizeT;
+ struct Pair {
+ T A, B;
+ };
+ ATTRIBUTE_NO_SANITIZE_ALL
+ void Insert(size_t Idx, const T &Arg1, const T &Arg2) {
+ Idx = Idx % kSize;
+ Table[Idx].A = Arg1;
+ Table[Idx].B = Arg2;
+ }
+
+ Pair Get(size_t I) { return Table[I % kSize]; }
+
+ Pair Table[kSize];
+};
+
+template <size_t kSizeT>
+struct MemMemTable {
+ static const size_t kSize = kSizeT;
+ Word MemMemWords[kSize];
+ Word EmptyWord;
+
+ void Add(const uint8_t *Data, size_t Size) {
+ if (Size <= 2) return;
+ Size = std::min(Size, Word::GetMaxSize());
+ size_t Idx = SimpleFastHash(Data, Size) % kSize;
+ MemMemWords[Idx].Set(Data, Size);
+ }
+ const Word &Get(size_t Idx) {
+ for (size_t i = 0; i < kSize; i++) {
+ const Word &W = MemMemWords[(Idx + i) % kSize];
+ if (W.size()) return W;
+ }
+ EmptyWord.Set(nullptr, 0);
+ return EmptyWord;
+ }
+};
+
+class TracePC {
+ public:
+ static const size_t kNumPCs = 1 << 21;
+ // How many bits of PC are used from __sanitizer_cov_trace_pc.
+ static const size_t kTracePcBits = 18;
+
+ void HandleInit(uint32_t *Start, uint32_t *Stop);
+ void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop);
+ void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop);
+ void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee);
+ template <class T> void HandleCmp(uintptr_t PC, T Arg1, T Arg2);
+ size_t GetTotalPCCoverage();
+ void SetUseCounters(bool UC) { UseCounters = UC; }
+ void SetUseClangCoverage(bool UCC) { UseClangCoverage = UCC; }
+ void SetUseValueProfile(bool VP) { UseValueProfile = VP; }
+ void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; }
+ void SetPrintNewFuncs(size_t P) { NumPrintNewFuncs = P; }
+ void UpdateObservedPCs();
+ template <class Callback> void CollectFeatures(Callback CB) const;
+
+ void ResetMaps() {
+ ValueProfileMap.Reset();
+ if (NumModules)
+ memset(Counters(), 0, GetNumPCs());
+ ClearExtraCounters();
+ ClearInlineCounters();
+ if (UseClangCoverage)
+ ClearClangCounters();
+ }
+
+ void ClearInlineCounters();
+
+ void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
+ void PrintFeatureSet();
+
+ void PrintModuleInfo();
+
+ void PrintCoverage();
+ void DumpCoverage();
+
+ void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
+ size_t n, bool StopAtZero);
+
+ TableOfRecentCompares<uint32_t, 32> TORC4;
+ TableOfRecentCompares<uint64_t, 32> TORC8;
+ TableOfRecentCompares<Word, 32> TORCW;
+ MemMemTable<1024> MMT;
+
+ size_t GetNumPCs() const {
+ return NumGuards == 0 ? (1 << kTracePcBits) : Min(kNumPCs, NumGuards + 1);
+ }
+ uintptr_t GetPC(size_t Idx) {
+ assert(Idx < GetNumPCs());
+ return PCs()[Idx];
+ }
+
+ void RecordInitialStack();
+ uintptr_t GetMaxStackOffset() const;
+
+ template<class CallBack>
+ void ForEachObservedPC(CallBack CB) {
+ for (auto PC : ObservedPCs)
+ CB(PC);
+ }
+
+private:
+ bool UseCounters = false;
+ bool UseValueProfile = false;
+ bool UseClangCoverage = false;
+ bool DoPrintNewPCs = false;
+ size_t NumPrintNewFuncs = 0;
+
+ struct Module {
+ uint32_t *Start, *Stop;
+ };
+
+ Module Modules[4096];
+ size_t NumModules; // linker-initialized.
+ size_t NumGuards; // linker-initialized.
+
+ struct { uint8_t *Start, *Stop; } ModuleCounters[4096];
+ size_t NumModulesWithInline8bitCounters; // linker-initialized.
+ size_t NumInline8bitCounters;
+
+ struct PCTableEntry {
+ uintptr_t PC, PCFlags;
+ };
+
+ struct { const PCTableEntry *Start, *Stop; } ModulePCTable[4096];
+ size_t NumPCTables;
+ size_t NumPCsInPCTables;
+
+ uint8_t *Counters() const;
+ uintptr_t *PCs() const;
+
+ Set<uintptr_t> ObservedPCs;
+ Set<uintptr_t> ObservedFuncs;
+
+ ValueBitMap ValueProfileMap;
+ uintptr_t InitialStack;
+};
+
+template <class Callback>
+// void Callback(size_t FirstFeature, size_t Idx, uint8_t Value);
+ATTRIBUTE_NO_SANITIZE_ALL
+void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End,
+ size_t FirstFeature, Callback Handle8bitCounter) {
+ typedef uintptr_t LargeType;
+ const size_t Step = sizeof(LargeType) / sizeof(uint8_t);
+ const size_t StepMask = Step - 1;
+ auto P = Begin;
+ // Iterate by 1 byte until either the alignment boundary or the end.
+ for (; reinterpret_cast<uintptr_t>(P) & StepMask && P < End; P++)
+ if (uint8_t V = *P)
+ Handle8bitCounter(FirstFeature, P - Begin, V);
+
+ // Iterate by Step bytes at a time.
+ for (; P < End; P += Step)
+ if (LargeType Bundle = *reinterpret_cast<const LargeType *>(P))
+ for (size_t I = 0; I < Step; I++, Bundle >>= 8)
+ if (uint8_t V = Bundle & 0xff)
+ Handle8bitCounter(FirstFeature, P - Begin + I, V);
+
+ // Iterate by 1 byte until the end.
+ for (; P < End; P++)
+ if (uint8_t V = *P)
+ Handle8bitCounter(FirstFeature, P - Begin, V);
+}
+
+// Given a non-zero Counter returns a number in the range [0,7].
+template<class T>
+unsigned CounterToFeature(T Counter) {
+ // Returns a feature number by placing Counters into buckets as illustrated
+ // below.
+ //
+ // Counter bucket: [1] [2] [3] [4-7] [8-15] [16-31] [32-127] [128+]
+ // Feature number: 0 1 2 3 4 5 6 7
+ //
+ // This is a heuristic taken from AFL (see
+ // http://lcamtuf.coredump.cx/afl/technical_details.txt).
+ //
+ // This implementation may change in the future so clients should
+ // not rely on it.
+ assert(Counter);
+ unsigned Bit = 0;
+ /**/ if (Counter >= 128) Bit = 7;
+ else if (Counter >= 32) Bit = 6;
+ else if (Counter >= 16) Bit = 5;
+ else if (Counter >= 8) Bit = 4;
+ else if (Counter >= 4) Bit = 3;
+ else if (Counter >= 3) Bit = 2;
+ else if (Counter >= 2) Bit = 1;
+ return Bit;
+}
+
+template <class Callback> // void Callback(size_t Feature)
+ATTRIBUTE_NO_SANITIZE_ADDRESS
+__attribute__((noinline))
+void TracePC::CollectFeatures(Callback HandleFeature) const {
+ uint8_t *Counters = this->Counters();
+ size_t N = GetNumPCs();
+ auto Handle8bitCounter = [&](size_t FirstFeature,
+ size_t Idx, uint8_t Counter) {
+ if (UseCounters)
+ HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Counter));
+ else
+ HandleFeature(FirstFeature + Idx);
+ };
+
+ size_t FirstFeature = 0;
+
+ if (!NumInline8bitCounters) {
+ ForEachNonZeroByte(Counters, Counters + N, FirstFeature, Handle8bitCounter);
+ FirstFeature += N * 8;
+ }
+
+ if (NumInline8bitCounters) {
+ for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
+ ForEachNonZeroByte(ModuleCounters[i].Start, ModuleCounters[i].Stop,
+ FirstFeature, Handle8bitCounter);
+ FirstFeature += 8 * (ModuleCounters[i].Stop - ModuleCounters[i].Start);
+ }
+ }
+
+ if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin()) {
+ auto P = ClangCountersBegin();
+ for (size_t Idx = 0; Idx < NumClangCounters; Idx++)
+ if (auto Cnt = P[Idx]) {
+ if (UseCounters)
+ HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Cnt));
+ else
+ HandleFeature(FirstFeature + Idx);
+ }
+ FirstFeature += NumClangCounters;
+ }
+
+ ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), FirstFeature,
+ Handle8bitCounter);
+ FirstFeature += (ExtraCountersEnd() - ExtraCountersBegin()) * 8;
+
+ if (UseValueProfile) {
+ ValueProfileMap.ForEach([&](size_t Idx) {
+ HandleFeature(FirstFeature + Idx);
+ });
+ FirstFeature += ValueProfileMap.SizeInBits();
+ }
+
+ // Step function, grows similar to 8 * Log_2(A).
+ auto StackDepthStepFunction = [](uint32_t A) -> uint32_t {
+ uint32_t Log2 = Log(A);
+ if (Log2 < 3) return A;
+ Log2 -= 3;
+ return (Log2 + 1) * 8 + ((A >> Log2) & 7);
+ };
+ assert(StackDepthStepFunction(1024) == 64);
+ assert(StackDepthStepFunction(1024 * 4) == 80);
+ assert(StackDepthStepFunction(1024 * 1024) == 144);
+
+ if (auto MaxStackOffset = GetMaxStackOffset())
+ HandleFeature(FirstFeature + StackDepthStepFunction(MaxStackOffset / 8));
+}
+
+extern TracePC TPC;
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_TRACE_PC
diff --git a/lib/fuzzer/FuzzerUtil.cpp b/lib/fuzzer/FuzzerUtil.cpp
new file mode 100644
index 000000000000..96b37d34815d
--- /dev/null
+++ b/lib/fuzzer/FuzzerUtil.cpp
@@ -0,0 +1,215 @@
+//===- FuzzerUtil.cpp - Misc utils ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Misc utils.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerUtil.h"
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include <cassert>
+#include <chrono>
+#include <cstring>
+#include <errno.h>
+#include <signal.h>
+#include <sstream>
+#include <stdio.h>
+#include <sys/types.h>
+#include <thread>
+
+namespace fuzzer {
+
+void PrintHexArray(const uint8_t *Data, size_t Size,
+ const char *PrintAfter) {
+ for (size_t i = 0; i < Size; i++)
+ Printf("0x%x,", (unsigned)Data[i]);
+ Printf("%s", PrintAfter);
+}
+
+void Print(const Unit &v, const char *PrintAfter) {
+ PrintHexArray(v.data(), v.size(), PrintAfter);
+}
+
+void PrintASCIIByte(uint8_t Byte) {
+ if (Byte == '\\')
+ Printf("\\\\");
+ else if (Byte == '"')
+ Printf("\\\"");
+ else if (Byte >= 32 && Byte < 127)
+ Printf("%c", Byte);
+ else
+ Printf("\\x%02x", Byte);
+}
+
+void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
+ for (size_t i = 0; i < Size; i++)
+ PrintASCIIByte(Data[i]);
+ Printf("%s", PrintAfter);
+}
+
+void PrintASCII(const Unit &U, const char *PrintAfter) {
+ PrintASCII(U.data(), U.size(), PrintAfter);
+}
+
+bool ToASCII(uint8_t *Data, size_t Size) {
+ bool Changed = false;
+ for (size_t i = 0; i < Size; i++) {
+ uint8_t &X = Data[i];
+ auto NewX = X;
+ NewX &= 127;
+ if (!isspace(NewX) && !isprint(NewX))
+ NewX = ' ';
+ Changed |= NewX != X;
+ X = NewX;
+ }
+ return Changed;
+}
+
+bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
+
+bool IsASCII(const uint8_t *Data, size_t Size) {
+ for (size_t i = 0; i < Size; i++)
+ if (!(isprint(Data[i]) || isspace(Data[i]))) return false;
+ return true;
+}
+
+bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
+ U->clear();
+ if (Str.empty()) return false;
+ size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R].
+ // Skip spaces from both sides.
+ while (L < R && isspace(Str[L])) L++;
+ while (R > L && isspace(Str[R])) R--;
+ if (R - L < 2) return false;
+ // Check the closing "
+ if (Str[R] != '"') return false;
+ R--;
+ // Find the opening "
+ while (L < R && Str[L] != '"') L++;
+ if (L >= R) return false;
+ assert(Str[L] == '\"');
+ L++;
+ assert(L <= R);
+ for (size_t Pos = L; Pos <= R; Pos++) {
+ uint8_t V = (uint8_t)Str[Pos];
+ if (!isprint(V) && !isspace(V)) return false;
+ if (V =='\\') {
+ // Handle '\\'
+ if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) {
+ U->push_back(Str[Pos + 1]);
+ Pos++;
+ continue;
+ }
+ // Handle '\xAB'
+ if (Pos + 3 <= R && Str[Pos + 1] == 'x'
+ && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) {
+ char Hex[] = "0xAA";
+ Hex[2] = Str[Pos + 2];
+ Hex[3] = Str[Pos + 3];
+ U->push_back(strtol(Hex, nullptr, 16));
+ Pos += 3;
+ continue;
+ }
+ return false; // Invalid escape.
+ } else {
+ // Any other character.
+ U->push_back(V);
+ }
+ }
+ return true;
+}
+
+bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units) {
+ if (Text.empty()) {
+ Printf("ParseDictionaryFile: file does not exist or is empty\n");
+ return false;
+ }
+ std::istringstream ISS(Text);
+ Units->clear();
+ Unit U;
+ int LineNo = 0;
+ std::string S;
+ while (std::getline(ISS, S, '\n')) {
+ LineNo++;
+ size_t Pos = 0;
+ while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces.
+ if (Pos == S.size()) continue; // Empty line.
+ if (S[Pos] == '#') continue; // Comment line.
+ if (ParseOneDictionaryEntry(S, &U)) {
+ Units->push_back(U);
+ } else {
+ Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo,
+ S.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string Base64(const Unit &U) {
+ static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ std::string Res;
+ size_t i;
+ for (i = 0; i + 2 < U.size(); i += 3) {
+ uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2];
+ Res += Table[(x >> 18) & 63];
+ Res += Table[(x >> 12) & 63];
+ Res += Table[(x >> 6) & 63];
+ Res += Table[x & 63];
+ }
+ if (i + 1 == U.size()) {
+ uint32_t x = (U[i] << 16);
+ Res += Table[(x >> 18) & 63];
+ Res += Table[(x >> 12) & 63];
+ Res += "==";
+ } else if (i + 2 == U.size()) {
+ uint32_t x = (U[i] << 16) + (U[i + 1] << 8);
+ Res += Table[(x >> 18) & 63];
+ Res += Table[(x >> 12) & 63];
+ Res += Table[(x >> 6) & 63];
+ Res += "=";
+ }
+ return Res;
+}
+
+std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {
+ if (!EF->__sanitizer_symbolize_pc) return "<can not symbolize>";
+ char PcDescr[1024] = {};
+ EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
+ SymbolizedFMT, PcDescr, sizeof(PcDescr));
+ PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case.
+ return PcDescr;
+}
+
+void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
+ if (EF->__sanitizer_symbolize_pc)
+ Printf("%s", DescribePC(SymbolizedFMT, PC).c_str());
+ else
+ Printf(FallbackFMT, PC);
+}
+
+unsigned NumberOfCpuCores() {
+ unsigned N = std::thread::hardware_concurrency();
+ if (!N) {
+ Printf("WARNING: std::thread::hardware_concurrency not well defined for "
+ "your platform. Assuming CPU count of 1.\n");
+ N = 1;
+ }
+ return N;
+}
+
+size_t SimpleFastHash(const uint8_t *Data, size_t Size) {
+ size_t Res = 0;
+ for (size_t i = 0; i < Size; i++)
+ Res = Res * 11 + Data[i];
+ return Res;
+}
+
+} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h
new file mode 100644
index 000000000000..f2ed028ce78e
--- /dev/null
+++ b/lib/fuzzer/FuzzerUtil.h
@@ -0,0 +1,87 @@
+//===- FuzzerUtil.h - Internal header for the Fuzzer Utils ------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Util functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_UTIL_H
+#define LLVM_FUZZER_UTIL_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerCommand.h"
+
+namespace fuzzer {
+
+void PrintHexArray(const Unit &U, const char *PrintAfter = "");
+
+void PrintHexArray(const uint8_t *Data, size_t Size,
+ const char *PrintAfter = "");
+
+void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = "");
+
+void PrintASCII(const Unit &U, const char *PrintAfter = "");
+
+// Changes U to contain only ASCII (isprint+isspace) characters.
+// Returns true iff U has been changed.
+bool ToASCII(uint8_t *Data, size_t Size);
+
+bool IsASCII(const Unit &U);
+
+bool IsASCII(const uint8_t *Data, size_t Size);
+
+std::string Base64(const Unit &U);
+
+void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC);
+
+std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC);
+
+unsigned NumberOfCpuCores();
+
+// Platform specific functions.
+void SetSignalHandler(const FuzzingOptions& Options);
+
+void SleepSeconds(int Seconds);
+
+unsigned long GetPid();
+
+size_t GetPeakRSSMb();
+
+int ExecuteCommand(const Command &Cmd);
+
+FILE *OpenProcessPipe(const char *Command, const char *Mode);
+
+const void *SearchMemory(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+
+std::string CloneArgsWithoutX(const Vector<std::string> &Args,
+ const char *X1, const char *X2);
+
+inline std::string CloneArgsWithoutX(const Vector<std::string> &Args,
+ const char *X) {
+ return CloneArgsWithoutX(Args, X, X);
+}
+
+inline std::pair<std::string, std::string> SplitBefore(std::string X,
+ std::string S) {
+ auto Pos = S.find(X);
+ if (Pos == std::string::npos)
+ return std::make_pair(S, "");
+ return std::make_pair(S.substr(0, Pos), S.substr(Pos));
+}
+
+std::string DisassembleCmd(const std::string &FileName);
+
+std::string SearchRegexCmd(const std::string &Regex);
+
+size_t SimpleFastHash(const uint8_t *Data, size_t Size);
+
+inline uint32_t Log(uint32_t X) { return 32 - __builtin_clz(X) - 1; }
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_UTIL_H
diff --git a/lib/fuzzer/FuzzerUtilDarwin.cpp b/lib/fuzzer/FuzzerUtilDarwin.cpp
new file mode 100644
index 000000000000..4bfbc11a50cf
--- /dev/null
+++ b/lib/fuzzer/FuzzerUtilDarwin.cpp
@@ -0,0 +1,162 @@
+//===- FuzzerUtilDarwin.cpp - Misc utils ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Misc utils for Darwin.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_APPLE
+#include "FuzzerCommand.h"
+#include "FuzzerIO.h"
+#include <mutex>
+#include <signal.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+
+// There is no header for this on macOS so declare here
+extern "C" char **environ;
+
+namespace fuzzer {
+
+static std::mutex SignalMutex;
+// Global variables used to keep track of how signal handling should be
+// restored. They should **not** be accessed without holding `SignalMutex`.
+static int ActiveThreadCount = 0;
+static struct sigaction OldSigIntAction;
+static struct sigaction OldSigQuitAction;
+static sigset_t OldBlockedSignalsSet;
+
+// This is a reimplementation of Libc's `system()`. On Darwin the Libc
+// implementation contains a mutex which prevents it from being used
+// concurrently. This implementation **can** be used concurrently. It sets the
+// signal handlers when the first thread enters and restores them when the last
+// thread finishes execution of the function and ensures this is not racey by
+// using a mutex.
+int ExecuteCommand(const Command &Cmd) {
+ std::string CmdLine = Cmd.toString();
+ posix_spawnattr_t SpawnAttributes;
+ if (posix_spawnattr_init(&SpawnAttributes))
+ return -1;
+ // Block and ignore signals of the current process when the first thread
+ // enters.
+ {
+ std::lock_guard<std::mutex> Lock(SignalMutex);
+ if (ActiveThreadCount == 0) {
+ static struct sigaction IgnoreSignalAction;
+ sigset_t BlockedSignalsSet;
+ memset(&IgnoreSignalAction, 0, sizeof(IgnoreSignalAction));
+ IgnoreSignalAction.sa_handler = SIG_IGN;
+
+ if (sigaction(SIGINT, &IgnoreSignalAction, &OldSigIntAction) == -1) {
+ Printf("Failed to ignore SIGINT\n");
+ (void)posix_spawnattr_destroy(&SpawnAttributes);
+ return -1;
+ }
+ if (sigaction(SIGQUIT, &IgnoreSignalAction, &OldSigQuitAction) == -1) {
+ Printf("Failed to ignore SIGQUIT\n");
+ // Try our best to restore the signal handlers.
+ (void)sigaction(SIGINT, &OldSigIntAction, NULL);
+ (void)posix_spawnattr_destroy(&SpawnAttributes);
+ return -1;
+ }
+
+ (void)sigemptyset(&BlockedSignalsSet);
+ (void)sigaddset(&BlockedSignalsSet, SIGCHLD);
+ if (sigprocmask(SIG_BLOCK, &BlockedSignalsSet, &OldBlockedSignalsSet) ==
+ -1) {
+ Printf("Failed to block SIGCHLD\n");
+ // Try our best to restore the signal handlers.
+ (void)sigaction(SIGQUIT, &OldSigQuitAction, NULL);
+ (void)sigaction(SIGINT, &OldSigIntAction, NULL);
+ (void)posix_spawnattr_destroy(&SpawnAttributes);
+ return -1;
+ }
+ }
+ ++ActiveThreadCount;
+ }
+
+ // NOTE: Do not introduce any new `return` statements past this
+ // point. It is important that `ActiveThreadCount` always be decremented
+ // when leaving this function.
+
+ // Make sure the child process uses the default handlers for the
+ // following signals rather than inheriting what the parent has.
+ sigset_t DefaultSigSet;
+ (void)sigemptyset(&DefaultSigSet);
+ (void)sigaddset(&DefaultSigSet, SIGQUIT);
+ (void)sigaddset(&DefaultSigSet, SIGINT);
+ (void)posix_spawnattr_setsigdefault(&SpawnAttributes, &DefaultSigSet);
+ // Make sure the child process doesn't block SIGCHLD
+ (void)posix_spawnattr_setsigmask(&SpawnAttributes, &OldBlockedSignalsSet);
+ short SpawnFlags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+ (void)posix_spawnattr_setflags(&SpawnAttributes, SpawnFlags);
+
+ pid_t Pid;
+ char **Environ = environ; // Read from global
+ const char *CommandCStr = CmdLine.c_str();
+ char *const Argv[] = {
+ strdup("sh"),
+ strdup("-c"),
+ strdup(CommandCStr),
+ NULL
+ };
+ int ErrorCode = 0, ProcessStatus = 0;
+ // FIXME: We probably shouldn't hardcode the shell path.
+ ErrorCode = posix_spawn(&Pid, "/bin/sh", NULL, &SpawnAttributes,
+ Argv, Environ);
+ (void)posix_spawnattr_destroy(&SpawnAttributes);
+ if (!ErrorCode) {
+ pid_t SavedPid = Pid;
+ do {
+ // Repeat until call completes uninterrupted.
+ Pid = waitpid(SavedPid, &ProcessStatus, /*options=*/0);
+ } while (Pid == -1 && errno == EINTR);
+ if (Pid == -1) {
+ // Fail for some other reason.
+ ProcessStatus = -1;
+ }
+ } else if (ErrorCode == ENOMEM || ErrorCode == EAGAIN) {
+ // Fork failure.
+ ProcessStatus = -1;
+ } else {
+ // Shell execution failure.
+ ProcessStatus = W_EXITCODE(127, 0);
+ }
+ for (unsigned i = 0, n = sizeof(Argv) / sizeof(Argv[0]); i < n; ++i)
+ free(Argv[i]);
+
+ // Restore the signal handlers of the current process when the last thread
+ // using this function finishes.
+ {
+ std::lock_guard<std::mutex> Lock(SignalMutex);
+ --ActiveThreadCount;
+ if (ActiveThreadCount == 0) {
+ bool FailedRestore = false;
+ if (sigaction(SIGINT, &OldSigIntAction, NULL) == -1) {
+ Printf("Failed to restore SIGINT handling\n");
+ FailedRestore = true;
+ }
+ if (sigaction(SIGQUIT, &OldSigQuitAction, NULL) == -1) {
+ Printf("Failed to restore SIGQUIT handling\n");
+ FailedRestore = true;
+ }
+ if (sigprocmask(SIG_BLOCK, &OldBlockedSignalsSet, NULL) == -1) {
+ Printf("Failed to unblock SIGCHLD\n");
+ FailedRestore = true;
+ }
+ if (FailedRestore)
+ ProcessStatus = -1;
+ }
+ }
+ return ProcessStatus;
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_APPLE
diff --git a/lib/fuzzer/FuzzerUtilFuchsia.cpp b/lib/fuzzer/FuzzerUtilFuchsia.cpp
new file mode 100644
index 000000000000..a5fdc37fb5a6
--- /dev/null
+++ b/lib/fuzzer/FuzzerUtilFuchsia.cpp
@@ -0,0 +1,228 @@
+//===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Misc utils implementation using Fuchsia/Zircon APIs.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_FUCHSIA
+
+#include "FuzzerInternal.h"
+#include "FuzzerUtil.h"
+#include <cerrno>
+#include <cinttypes>
+#include <cstdint>
+#include <fbl/unique_fd.h>
+#include <fcntl.h>
+#include <launchpad/launchpad.h>
+#include <string>
+#include <thread>
+#include <zircon/errors.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/port.h>
+#include <zircon/types.h>
+#include <zx/object.h>
+#include <zx/port.h>
+#include <zx/process.h>
+#include <zx/time.h>
+
+namespace fuzzer {
+
+namespace {
+
+// A magic value for the Zircon exception port, chosen to spell 'FUZZING'
+// when interpreted as a byte sequence on little-endian platforms.
+const uint64_t kFuzzingCrash = 0x474e495a5a5546;
+
+void AlarmHandler(int Seconds) {
+ while (true) {
+ SleepSeconds(Seconds);
+ Fuzzer::StaticAlarmCallback();
+ }
+}
+
+void InterruptHandler() {
+ // Ctrl-C sends ETX in Zircon.
+ while (getchar() != 0x03);
+ Fuzzer::StaticInterruptCallback();
+}
+
+void CrashHandler(zx::port *Port) {
+ std::unique_ptr<zx::port> ExceptionPort(Port);
+ zx_port_packet_t Packet;
+ ExceptionPort->wait(ZX_TIME_INFINITE, &Packet, 0);
+ // Unbind as soon as possible so we don't receive exceptions from this thread.
+ if (zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID,
+ kFuzzingCrash, 0) != ZX_OK) {
+ // Shouldn't happen; if it does the safest option is to just exit.
+ Printf("libFuzzer: unable to unbind exception port; aborting!\n");
+ exit(1);
+ }
+ if (Packet.key != kFuzzingCrash) {
+ Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n",
+ Packet.key);
+ exit(1);
+ }
+ // CrashCallback should not return from this call
+ Fuzzer::StaticCrashSignalCallback();
+}
+
+} // namespace
+
+// Platform specific functions.
+void SetSignalHandler(const FuzzingOptions &Options) {
+ zx_status_t rc;
+
+ // Set up alarm handler if needed.
+ if (Options.UnitTimeoutSec > 0) {
+ std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
+ T.detach();
+ }
+
+ // Set up interrupt handler if needed.
+ if (Options.HandleInt || Options.HandleTerm) {
+ std::thread T(InterruptHandler);
+ T.detach();
+ }
+
+ // Early exit if no crash handler needed.
+ if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
+ !Options.HandleFpe && !Options.HandleAbrt)
+ return;
+
+ // Create an exception port
+ zx::port *ExceptionPort = new zx::port();
+ if ((rc = zx::port::create(0, ExceptionPort)) != ZX_OK) {
+ Printf("libFuzzer: zx_port_create failed: %s\n", zx_status_get_string(rc));
+ exit(1);
+ }
+
+ // Bind the port to receive exceptions from our process
+ if ((rc = zx_task_bind_exception_port(zx_process_self(), ExceptionPort->get(),
+ kFuzzingCrash, 0)) != ZX_OK) {
+ Printf("libFuzzer: unable to bind exception port: %s\n",
+ zx_status_get_string(rc));
+ exit(1);
+ }
+
+ // Set up the crash handler.
+ std::thread T(CrashHandler, ExceptionPort);
+ T.detach();
+}
+
+void SleepSeconds(int Seconds) {
+ zx::nanosleep(zx::deadline_after(ZX_SEC(Seconds)));
+}
+
+unsigned long GetPid() {
+ zx_status_t rc;
+ zx_info_handle_basic_t Info;
+ if ((rc = zx_object_get_info(zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
+ sizeof(Info), NULL, NULL)) != ZX_OK) {
+ Printf("libFuzzer: unable to get info about self: %s\n",
+ zx_status_get_string(rc));
+ exit(1);
+ }
+ return Info.koid;
+}
+
+size_t GetPeakRSSMb() {
+ zx_status_t rc;
+ zx_info_task_stats_t Info;
+ if ((rc = zx_object_get_info(zx_process_self(), ZX_INFO_TASK_STATS, &Info,
+ sizeof(Info), NULL, NULL)) != ZX_OK) {
+ Printf("libFuzzer: unable to get info about self: %s\n",
+ zx_status_get_string(rc));
+ exit(1);
+ }
+ return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
+}
+
+int ExecuteCommand(const Command &Cmd) {
+ zx_status_t rc;
+
+ // Convert arguments to C array
+ auto Args = Cmd.getArguments();
+ size_t Argc = Args.size();
+ assert(Argc != 0);
+ std::unique_ptr<const char *[]> Argv(new const char *[Argc]);
+ for (size_t i = 0; i < Argc; ++i)
+ Argv[i] = Args[i].c_str();
+
+ // Create the basic launchpad. Clone everything except stdio.
+ launchpad_t *lp;
+ launchpad_create(ZX_HANDLE_INVALID, Argv[0], &lp);
+ launchpad_load_from_file(lp, Argv[0]);
+ launchpad_set_args(lp, Argc, Argv.get());
+ launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_FDIO_STDIO));
+
+ // Determine stdout
+ int FdOut = STDOUT_FILENO;
+ fbl::unique_fd OutputFile;
+ if (Cmd.hasOutputFile()) {
+ auto Filename = Cmd.getOutputFile();
+ OutputFile.reset(open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0));
+ if (!OutputFile) {
+ Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),
+ strerror(errno));
+ return ZX_ERR_IO;
+ }
+ FdOut = OutputFile.get();
+ }
+
+ // Determine stderr
+ int FdErr = STDERR_FILENO;
+ if (Cmd.isOutAndErrCombined())
+ FdErr = FdOut;
+
+ // Clone the file descriptors into the new process
+ if ((rc = launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO)) != ZX_OK ||
+ (rc = launchpad_clone_fd(lp, FdOut, STDOUT_FILENO)) != ZX_OK ||
+ (rc = launchpad_clone_fd(lp, FdErr, STDERR_FILENO)) != ZX_OK) {
+ Printf("libFuzzer: failed to clone FDIO: %s\n", zx_status_get_string(rc));
+ return rc;
+ }
+
+ // Start the process
+ zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
+ const char *ErrorMsg = nullptr;
+ if ((rc = launchpad_go(lp, &ProcessHandle, &ErrorMsg)) != ZX_OK) {
+ Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
+ zx_status_get_string(rc));
+ return rc;
+ }
+ zx::process Process(ProcessHandle);
+
+ // Now join the process and return the exit status.
+ if ((rc = Process.wait_one(ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE,
+ nullptr)) != ZX_OK) {
+ Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
+ zx_status_get_string(rc));
+ return rc;
+ }
+
+ zx_info_process_t Info;
+ if ((rc = Process.get_info(ZX_INFO_PROCESS, &Info, sizeof(Info), nullptr,
+ nullptr)) != ZX_OK) {
+ Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
+ zx_status_get_string(rc));
+ return rc;
+ }
+
+ return Info.return_code;
+}
+
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+ size_t PattLen) {
+ return memmem(Data, DataLen, Patt, PattLen);
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_FUCHSIA
diff --git a/lib/fuzzer/FuzzerUtilLinux.cpp b/lib/fuzzer/FuzzerUtilLinux.cpp
new file mode 100644
index 000000000000..c7cf2c0a778b
--- /dev/null
+++ b/lib/fuzzer/FuzzerUtilLinux.cpp
@@ -0,0 +1,26 @@
+//===- FuzzerUtilLinux.cpp - Misc utils for Linux. ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Misc utils for Linux.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD
+#include "FuzzerCommand.h"
+
+#include <stdlib.h>
+
+namespace fuzzer {
+
+int ExecuteCommand(const Command &Cmd) {
+ std::string CmdLine = Cmd.toString();
+ return system(CmdLine.c_str());
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_LINUX || LIBFUZZER_NETBSD
diff --git a/lib/fuzzer/FuzzerUtilPosix.cpp b/lib/fuzzer/FuzzerUtilPosix.cpp
new file mode 100644
index 000000000000..934b7aa98ff1
--- /dev/null
+++ b/lib/fuzzer/FuzzerUtilPosix.cpp
@@ -0,0 +1,151 @@
+//===- FuzzerUtilPosix.cpp - Misc utils for Posix. ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Misc utils implementation using Posix API.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_POSIX
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include <cassert>
+#include <chrono>
+#include <cstring>
+#include <errno.h>
+#include <iomanip>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <thread>
+#include <unistd.h>
+
+namespace fuzzer {
+
+static void AlarmHandler(int, siginfo_t *, void *) {
+ Fuzzer::StaticAlarmCallback();
+}
+
+static void CrashHandler(int, siginfo_t *, void *) {
+ Fuzzer::StaticCrashSignalCallback();
+}
+
+static void InterruptHandler(int, siginfo_t *, void *) {
+ Fuzzer::StaticInterruptCallback();
+}
+
+static void GracefulExitHandler(int, siginfo_t *, void *) {
+ Fuzzer::StaticGracefulExitCallback();
+}
+
+static void FileSizeExceedHandler(int, siginfo_t *, void *) {
+ Fuzzer::StaticFileSizeExceedCallback();
+}
+
+static void SetSigaction(int signum,
+ void (*callback)(int, siginfo_t *, void *)) {
+ struct sigaction sigact = {};
+ if (sigaction(signum, nullptr, &sigact)) {
+ Printf("libFuzzer: sigaction failed with %d\n", errno);
+ exit(1);
+ }
+ if (sigact.sa_flags & SA_SIGINFO) {
+ if (sigact.sa_sigaction)
+ return;
+ } else {
+ if (sigact.sa_handler != SIG_DFL && sigact.sa_handler != SIG_IGN &&
+ sigact.sa_handler != SIG_ERR)
+ return;
+ }
+
+ sigact = {};
+ sigact.sa_sigaction = callback;
+ if (sigaction(signum, &sigact, 0)) {
+ Printf("libFuzzer: sigaction failed with %d\n", errno);
+ exit(1);
+ }
+}
+
+void SetTimer(int Seconds) {
+ struct itimerval T {
+ {Seconds, 0}, { Seconds, 0 }
+ };
+ if (setitimer(ITIMER_REAL, &T, nullptr)) {
+ Printf("libFuzzer: setitimer failed with %d\n", errno);
+ exit(1);
+ }
+ SetSigaction(SIGALRM, AlarmHandler);
+}
+
+void SetSignalHandler(const FuzzingOptions& Options) {
+ if (Options.UnitTimeoutSec > 0)
+ SetTimer(Options.UnitTimeoutSec / 2 + 1);
+ if (Options.HandleInt)
+ SetSigaction(SIGINT, InterruptHandler);
+ if (Options.HandleTerm)
+ SetSigaction(SIGTERM, InterruptHandler);
+ if (Options.HandleSegv)
+ SetSigaction(SIGSEGV, CrashHandler);
+ if (Options.HandleBus)
+ SetSigaction(SIGBUS, CrashHandler);
+ if (Options.HandleAbrt)
+ SetSigaction(SIGABRT, CrashHandler);
+ if (Options.HandleIll)
+ SetSigaction(SIGILL, CrashHandler);
+ if (Options.HandleFpe)
+ SetSigaction(SIGFPE, CrashHandler);
+ if (Options.HandleXfsz)
+ SetSigaction(SIGXFSZ, FileSizeExceedHandler);
+ if (Options.HandleUsr1)
+ SetSigaction(SIGUSR1, GracefulExitHandler);
+ if (Options.HandleUsr2)
+ SetSigaction(SIGUSR2, GracefulExitHandler);
+}
+
+void SleepSeconds(int Seconds) {
+ sleep(Seconds); // Use C API to avoid coverage from instrumented libc++.
+}
+
+unsigned long GetPid() { return (unsigned long)getpid(); }
+
+size_t GetPeakRSSMb() {
+ struct rusage usage;
+ if (getrusage(RUSAGE_SELF, &usage))
+ return 0;
+ if (LIBFUZZER_LINUX) {
+ // ru_maxrss is in KiB
+ return usage.ru_maxrss >> 10;
+ } else if (LIBFUZZER_APPLE) {
+ // ru_maxrss is in bytes
+ return usage.ru_maxrss >> 20;
+ }
+ assert(0 && "GetPeakRSSMb() is not implemented for your platform");
+ return 0;
+}
+
+FILE *OpenProcessPipe(const char *Command, const char *Mode) {
+ return popen(Command, Mode);
+}
+
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+ size_t PattLen) {
+ return memmem(Data, DataLen, Patt, PattLen);
+}
+
+std::string DisassembleCmd(const std::string &FileName) {
+ return "objdump -d " + FileName;
+}
+
+std::string SearchRegexCmd(const std::string &Regex) {
+ return "grep '" + Regex + "'";
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_POSIX
diff --git a/lib/fuzzer/FuzzerUtilWindow